Skip to content

Publishing

Store a publish key, name the source, publish events from an app, and set each event's fields and lifetime.

Access: Keys with the events:publish scope, issued by Albastar Corp.

An app publishes events into one source with a publish key.

Get a publish key

  1. Albastar Corp. creates the source (slug [a-z0-9-]{2,48}, name, icon, colour, retention) and issues an abk_ publish key bound to the source.
  2. Store the key on the app's server as ALBASTAR_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 URL, 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.

FieldContent
nameThe service as readers know it: Vercel, Stripe, GitHub
iconA Simple Icons slug (vercel) or an SF Symbol name (shippingbox.fill); an SF Symbol draws only on readers built for Apple platforms
colorThe 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 (web, api), not in the source name.

Shell
curl -X PATCH https://api.albastov.com/v1/events/sources/self \
  -H "Authorization: Bearer $ALBASTAR_EVENTS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Vercel", "icon": "vercel", "color": "#000000"}'
Response
{
  "slug": "vercel",
  "name": "Vercel",
  "icon": "vercel",
  "color": "#000000"
}

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 $ALBASTAR_EVENTS_KEY" \
  -H "Content-Type: application/json" \
  --max-time 5 \
  -d '{
    "type": "deploy.failed",
    "severity": "error",
    "text": "Deploy **failed** `9f3c2e1`",
    "detail": "npm run build exited 1",
    "subject": "web",
    "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** `9f3c2e1`",
        "detail": "npm run build exited 1",
        "subject": "web",
        "display": {"lifetime": "sticky"},
        "idempotency_key": "deploy-9f3c2e1",
    }).encode(),
    headers={
        "User-Agent": "my-app/1.0",
        "Authorization": f"Bearer {os.environ['ALBASTAR_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.ALBASTAR_EVENTS_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    type: "deploy.failed",
    severity: "error",
    text: "Deploy **failed** `9f3c2e1`",
    detail: "npm run build exited 1",
    subject: "web",
    display: { lifetime: "sticky" },
    idempotency_key: "deploy-9f3c2e1",
  }),
  signal: AbortSignal.timeout(5000),
});
console.log(res.status, (await res.json()).id);
Response
{
  "id": "evt_01M6GDQMZRD7F5H9K3M6P8R1T4",
  "cursor": "1752",
  "source": "vercel",
  "source_name": "Vercel",
  "source_color": "#000000",
  "source_icon": "vercel",
  "type": "deploy.failed",
  "severity": "error",
  "text": "Deploy **failed** `9f3c2e1`",
  "detail": "npm run build exited 1",
  "subject": "web",
  "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.

Event fields

FieldContent
typeWhat happened, as a dotted noun: deploy.failed, pr.merged, backup.done
severitydebug, info, notice, warn, error or critical; default info
textThe notice as one line, with inline **bold**, *italic* and `code`
detailPlain text under the line, newlines allowed
subjectThe part of the service the event concerns: web, api
urlAn https:// link to the deploy, order or incident
occurred_atWhen the event happened; default the time of receipt
displayPresentation hints for readers: lifetime, layout, effect, target, period, color
dataA JSON object stored as sent

The API adds id, cursor, source, source_name, source_color, source_icon, received_at and, per read key, dismissed_at. Lengths, formats and every display value: Publish an event.

SeverityUse for
debugWiring tests
infoCompleted work: deploy done, PR merged, backup done, sale
noticeItems to read: PR opened, new signup, configuration change
warnDegraded service: retries, slow responses, disk at 85%
errorFailures that need a person: deploy failed, site down
criticalMoney, data or security at risk now

display.lifetime sets how long a reader shows an event: whole seconds 1..86400, or "sticky". A sticky event stays on screen until a reader dismisses the event. Use "sticky" for states that last until a person acts: a site down, a failed deploy. Without lifetime, the reader's own default applies. Dismissal belongs to the read key: Read keys.

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.

Shell
curl https://api.albastov.com/v1/events/batch \
  -H "Authorization: Bearer $ALBASTAR_EVENTS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {"type": "deploy.succeeded", "text": "Deploy **done**", "subject": "web"},
      {"type": "deploy.succeeded", "text": "Deploy **done**", "subject": "docs"}
    ]
  }'

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.

ResponseAction
Network error, 5xxRetry at most 3 times with growing waits plus jitter, for example 1 s, 4 s and 15 s; then drop the event and log one line
429Wait the Retry-After seconds, then retry within the same 3 attempts
400, 401, 403, 413Do not retry; log message

Rates and body sizes: Events limits.

History

A source keeps events for 90 days unless Albastar Corp. sets another retention, from 1 to 3,650 days. An archived source takes no new events from publish keys or webhooks; its history stays readable until retention removes it.

Reference

  • Events reference: fields, display values, responses and error codes for POST /v1/events, POST /v1/events/batch and PATCH /v1/events/sources/self.