An app publishes events into one source with a publish key.
Add a source
- On the albastov.com admin panel, open Events and create a source: slug (
[a-z0-9-]{2,48}), name, icon, colour and retention in days (default 90). - Mint a publish key for the source. The panel shows the
abk_secret once, with a brief for the app's developer or coding agent. - Store the key on the app's server as
ALBASTOV_EVENTS_KEY. Keep the key out of browser bundles, mobile apps, repositories and log lines.
A source takes events from publish keys, from a webhook, or both.
Name the source
Readers show every event beside its source's name, icon and colour. Set them once from the app with
PATCH /v1/events/sources/self; the change applies to the source's whole history.
| Field | Content |
|---|---|
name | The service as readers know it: Stripe, GitHub, Shop |
icon | A Simple Icons slug (stripe) or an SF Symbol name (shippingbox.fill) |
color | The brand colour: #rgb, #rrggbb or #rrggbbaa |
Use one source per service a reader recognises. Put the part of the service in each event's subject (api,
checkout), not in the source name.
curl
curl -X PATCH https://api.albastov.com/v1/events/sources/self \
-H "Authorization: Bearer $ALBASTOV_EVENTS_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Sentry", "icon": "sentry", "color": "#362d59"}'{"slug": "sentry", "name": "Sentry", "icon": "sentry", "color": "#362d59"}Publish an event
POST /v1/events stores one event in the key's source and returns the stored event. The source comes from the key:
leave source out.
curl
curl https://api.albastov.com/v1/events \
-H "Authorization: Bearer $ALBASTOV_EVENTS_KEY" \
-H "Content-Type: application/json" \
--max-time 5 \
-d '{"type": "deploy.failed", "severity": "error", "text": "Deploy **failed** on web `9f3c2e1`", "detail": "npm run build exited 1", "display": {"lifetime": "sticky"}, "idempotency_key": "deploy-9f3c2e1"}'Python
import json, os, urllib.request
req = urllib.request.Request(
"https://api.albastov.com/v1/events",
data=json.dumps({
"type": "deploy.failed",
"severity": "error",
"text": "Deploy **failed** on web `9f3c2e1`",
"detail": "npm run build exited 1",
"display": {"lifetime": "sticky"},
"idempotency_key": "deploy-9f3c2e1",
}).encode(),
headers={
"User-Agent": "my-app/1.0",
"Authorization": f"Bearer {os.environ['ALBASTOV_EVENTS_KEY']}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req, timeout=5) as res:
print(res.status, json.load(res)["id"])JavaScript
const res = await fetch("https://api.albastov.com/v1/events", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ALBASTOV_EVENTS_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
type: "deploy.failed",
severity: "error",
text: "Deploy **failed** on web `9f3c2e1`",
detail: "npm run build exited 1",
display: { lifetime: "sticky" },
idempotency_key: "deploy-9f3c2e1",
}),
signal: AbortSignal.timeout(5000),
});
console.log(res.status, (await res.json()).id);{"id": "evt_01JBX7Q2W8V5K3M9N4P6R2T8YC", "cursor": "1734", "source": "web", "source_name": "Web", "source_color": null, "source_icon": null, "type": "deploy.failed", "severity": "error", "text": "Deploy **failed** on web `9f3c2e1`", "detail": "npm run build exited 1", "subject": null, "url": null, "occurred_at": "2026-11-03T10:02:03Z", "received_at": "2026-11-03T10:02:03Z", "display": {"lifetime": "sticky"}, "data": null, "dismissed_at": null}Name the type as a dotted noun (deploy.succeeded, pr.merged, site.down) and keep text to one line a person
reads at a glance. Mark states that last until a person acts with "display": {"lifetime": "sticky"}. Severity
guidance: Event fields.
Publish a batch
POST /v1/events/batch publishes 1 to 100 events in one request, as {"events": [...]}. One invalid event refuses
the whole batch, and the error's meta.index names the event. The response lists the stored events in request order,
with status 201 when at least one event is new, else 200.
curl https://api.albastov.com/v1/events/batch \
-H "Authorization: Bearer $ALBASTOV_EVENTS_KEY" \
-H "Content-Type: application/json" \
-d '{"events": [{"type": "job.done", "text": "Job **export** done"}, {"type": "job.done", "text": "Job **import** done"}]}'Dedupe
Set idempotency_key on every event the app may send twice: deploy-<sha>, backup-2026-11-03. A key used again
on the same source within 7 days returns the original event with 200 and stores nothing.
Retries
Publish outside the request path, with a 5 s timeout. A failed publish must not block, slow down or fail the app.
| Response | Action |
|---|---|
Network error, 5xx | Retry at most 3 times, after 1 s, 4 s and 15 s plus jitter; then drop the event and log one line |
429 | Wait the Retry-After seconds, then retry within the same 3 attempts |
400, 401, 403, 413 | Do not retry; log message |
Rates and body sizes: Limits.
Reference
- Events reference: fields,
displayvalues, responses and error codes forPOST /v1/events,POST /v1/events/batchandPATCH /v1/events/sources/self.