Ablo · AsyncAPI Specification

Abloatai Webhooks

Version

View Spec View on GitHub Agent Infrastructuremulti-agent-coordinationconcurrency-controlState ManagementDatabasePostgresreal-time-syncMCPDeveloper Toolsbackend-infrastructureAsyncAPIWebhooksEvents

AsyncAPI Specification

Raw ↑
generated: '2026-08-19'
method: searched
source: https://docs.abloatai.com/webhooks
spec_type: none
asyncapi_published: false
asyncapi_note: >-
  No AsyncAPI document is published. Ablo has TWO event surfaces — a signed webhook stream and a WSS
  realtime stream — and neither has a machine-readable event contract; /asyncapi.yaml, /asyncapi.json
  and the GitHub monorepo all miss. The event catalog below is captured from the prose docs.
surfaces:
  - kind: webhooks
    docs: https://docs.abloatai.com/webhooks
    description: 'The committed transaction log streamed to your own systems as signed HTTP POSTs.'
  - kind: websocket
    transport: WSS
    description: 'Realtime sync to live clients for optimistic UI (useAblo). Carries the same error envelope as HTTP.'
    contract: none published
webhooks:
  signature_scheme: Standard Webhooks
  signature_spec: https://www.standardwebhooks.com
  signature_headers: [webhook-id, webhook-timestamp, webhook-signature]
  replay_window: 5 minutes
  verification_note: >-
    Ablo ships no verification code of its own — you use the open svix or standardwebhooks library.
    Verify against the RAW request body; frameworks that re-serialize JSON break the signature.
  secret_prefix: whsec_
  secret_disclosure: 'Minted once at registration and returned a single time; the CLI writes it to .env.local.'
  registration:
    cli: 'npx ablo webhooks create <url> [--events <models>] [--description <label>]'
    api: 'POST https://api.abloatai.com/api/v1/webhook_endpoints'
    api_note: >-
      This endpoint is documented on the webhooks page with a working curl example but is NOT in the
      published OpenAPI, which covers only 22 paths and does not include webhook_endpoints. The
      webhook management surface is therefore undiscoverable from the machine-readable contract.
    endpoint_id_prefix: we_
    management:
      - {command: 'ablo webhooks list', does: 'endpoints plus delivery health (status, cursor, last error)'}
      - {command: 'ablo webhooks roll <id>', does: 'mint a fresh signing secret'}
      - {command: 'ablo webhooks enable <id>', does: 're-enable a disabled endpoint'}
      - {command: 'ablo webhooks rm <id>', does: 'remove an endpoint'}
  delivery:
    guarantee: at-least-once, in order
    mechanism: 'Per-endpoint cursor over the log, advancing only on a 2xx. A failed delivery leaves the cursor in place so the same events are re-sent until they land.'
    batching: 'Every delivery is a batch of events.'
    ordering_key: syncId
    ordering_note: 'syncId is a monotonic log position — dedupe AND order by it. Ablo guarantees the order because it owns the log.'
    ack: 'Any non-2xx (or no response within the timeout) is a failure.'
    retries: 'immediate, 5s, 5m, 30m, 2h, 5h, 10h, 10h — 8 attempts over roughly 32 hours'
    auto_disable: 'After the retries exhaust the endpoint is marked disabled and delivery stops until `ablo webhooks enable <id>`.'
    replay: 'Nothing is lost on failure — the log IS the durable buffer; delivery resumes from the cursor once healthy.'
  event_envelope:
    batch_field: data
    fields:
      - {field: type, meaning: '"<model>.<verb>" with the model name lowercased, e.g. record.updated'}
      - {field: model, meaning: 'the model name exactly as declared in your schema — the table to write'}
      - {field: objectId, meaning: "the changed row's id"}
      - {field: data, meaning: 'the post-change row, or null on delete'}
      - {field: syncId, meaning: 'monotonic log position — dedupe and order by this'}
      - {field: id, meaning: 'String(syncId): the event id'}
      - {field: createdAt, meaning: 'ISO commit timestamp'}
    typescript_type: "import type { AbloWebhookEvent } from '@abloatai/abloatai/webhooks'"
  event_types:
    pattern: '<model>.<verb>'
    verbs:
      - {type: '<model>.created', when: 'a row was inserted'}
      - {type: '<model>.updated', when: 'a row was updated'}
      - {type: '<model>.deleted', when: 'a row was deleted (data is null)'}
      - {type: '<model>.archived', when: 'a row was soft-archived'}
      - {type: '<model>.unarchived', when: 'a soft-archived row was restored'}
    scoping: 'enabledEvents defaults to ["*"] (every model). Internal coordination changes (permissions, sync groups) carry NO webhook — only your data models produce events.'
    dynamic: >-
      The event type set is a function of the CUSTOMER'S pushed schema, not a fixed provider
      catalog. That is precisely why an AsyncAPI document would have to be generated per project
      rather than published once, and is the honest reason none exists.
  local_testing: 'ablo dev prepares an isolated schema branch but does NOT forward webhook deliveries. Register an HTTPS tunnel URL and remove the endpoint when finished.'
  alternative: 'ablo connect — Ablo reads your write-ahead log and writes back through a scoped role. The webhook path gives Ablo no database credentials at all.'
x-evidence:
  - {url: 'https://docs.abloatai.com/webhooks', http_status: 200}