Boom Ai · AsyncAPI Specification

Boom Ai Webhooks

Version

View Spec View on GitHub CompanyArtificial IntelligenceConversational AICustomer EngagementCustomer Data PlatformMessagingWhatsAppSMSMarketing AutomationE-CommerceAgentsMCPAsyncAPIWebhooksEvents

AsyncAPI Specification

Raw ↑
generated: '2026-08-13'
method: searched
source: https://docs.useboom.ai/webhooks
spec_type: none
asyncapi_published: false
asyncapi_note: >-
  Boom publishes NO AsyncAPI document — probed the docs host and the BOOM-TML GitHub org.
  The webhook surface below is captured from the provider's own prose reference and is
  recorded as a Webhooks catalog, not as a machine-readable event contract. Nothing here
  is invented; payload field lists are the ones Boom prints.
surface:
  direction: outbound
  protocol: HTTPS POST
  content_type: application/json
  enablement: per-workspace, off by default (Settings -> Webhooks; requires Settings -> HTTP Credentials)
  configuration: UI only — subscriptions are created in the Boom app, not over the API
  related_api: GET /api/v1/http-credentials (http_credentials_list) lists the credentials a subscription can use
  timeout_seconds: 10
envelope:
  fields:
    - {name: id, description: 'Event id (e.g. evt_cm7x…); also sent as the Idempotency-Key request header'}
    - {name: type, description: The event type, or "ping" for the synthetic test delivery}
    - {name: occurredAt, description: ISO 8601 timestamp}
    - {name: organizationId, description: The Boom organization the event belongs to}
    - {name: data, description: Event-specific payload}
  idempotency_header: Idempotency-Key
events:
  - name: journey_run.started
    fires_when: Someone was enrolled and their run began — at enrollment, BEFORE the first message is sent. Not a delivery receipt.
    payload_keys: [run, trigger, startedAt]
    run_fields: [engagementId, initiativeId, initiativeName, workflowId, customerId, personId, personExternalId]
    trigger_kinds:
      - {kind: cdp_event, extra: [eventName, eventId]}
      - {kind: segment, extra: [segmentId]}
      - {kind: manual, extra: []}
    gotcha: >-
      personId is frequently null — populated only on the CDP-event enrollment path.
      Join on personExternalId (your own id) instead.
  - name: journey_run.ended
    fires_when: The run reached a terminal state, however it ended. May be days after started; durationMs gives the real gap.
    payload_keys: [run, outcome]
    outcome_fields: [status, reason, lastSignal, terminalNode, error, startedAt, endedAt, durationMs, messagesSent, messagesReceived]
    reasons: [completed, no_reply, abandoned, failed_node_error, failed_engine, canceled_operator,
              canceled_initiative, canceled_participant_stop, expired]
    signals: [REPLIED, CLOSED, TIMEOUT, STALE, null]
    gotcha: >-
      Branch on reason, not status — three materially different endings all land on
      status CONVERSATION_COMPLETE. `expired` is reserved and cannot currently occur.
      outcome.error is an object ({errorName}) or null, never a message or stack.
  - name: enrollment.rejected
    fires_when: A CDP event matched a journey trigger but no run started. CDP-event path only — segment, manual, CSV and API enrollment never emit it.
    payload_keys: [reason, detail, initiativeId, workflowId, eventName, eventId, personId, personExternalId, customerId]
    reasons:
      - {reason: no_channel, means: No reachable phone or email for this person}
      - {reason: active_run, means: Already in a live run of this journey, detail: existingEngagementId}
      - {reason: frequency_cap, means: Hit the initiative's enrollment cap, detail: 'count, window'}
      - {reason: no_workflow, means: The journey stopped being published mid-flight}
      - {reason: internal_error, means: Enrollment failed after retries, detail: errorName}
    gotcha: '"No trigger matched" does not emit. Treat initiativeId and workflowId as nullable.'
  - name: ping
    fires_when: Someone clicks the test-delivery button. Nothing subscribes to it.
    payload_keys: [id, type, occurredAt, organizationId, data]
    gotcha: Handle as a no-op (return 2xx and ignore) so a colleague's test never reads as a real run.
security:
  authentication: >-
    A credential is REQUIRED and must actually authenticate — BEARER, API_KEY (header or
    query parameter) or BASIC. A "No authentication" credential cannot be attached: it is
    greyed out in the picker, rejected on save, and refused at delivery rather than sent
    unsigned.
  signature: none — authenticity is proven by the credential Boom sends, not by a payload signature
  url_requirements: >-
    Must start with a literal https:// (plain http rejected on save). Private and loopback
    addresses save but are blocked at delivery.
  per_environment: >-
    A subscription URL may reference {{env.KEY}}, and credential keys may have a global row
    plus per-environment overrides. A key with no row for an environment and no global row
    causes deliveries to be DROPPED, not sent unauthenticated.
delivery:
  guarantee: at-least-once delivery, at-most-once emission
  dedupe_on: id
  retries:
    - {response: 2xx, behavior: delivered}
    - {response: '5xx, 408, 429', behavior: retried up to 3 times — 4 attempts total}
    - {response: no response (timeout, DNS, connection reset), behavior: retried up to 3 times}
    - {response: any other 4xx, behavior: permanent — not retried (includes 401 and 403)}
  reconciliation_warning: >-
    Boom states plainly that webhooks are NOT a source of truth: if emission fails the run
    is permanently unreported and no retry recovers it, and a subscription with an
    unresolvable credential or {{env.*}} token drops the event outright. Consumers must
    reconcile periodically rather than treat the stream as a ledger.
  head_of_line_warning: >-
    Deliveries for one event are attempted in sequence; a retryable failure on one
    subscription interrupts the pass and can starve the subscriptions after it.
x-evidence:
  - {url: 'https://docs.useboom.ai/webhooks.md', status: 200, checked: '2026-08-13'}