Connect by JBRH Open Connect

AsyncAPI

AsyncAPI describes an interface where messages arrive rather than being requested: channels, the operations that send or receive on them, and the message envelope. Connect publishes one at /developers/asyncapi.yaml to 3.1.0, covering outbound webhooks — one channel, one envelope, signed.

Status
Reference What this means
Audience
developer
Last verified
Product version
6.3.2

Why request/response description does not fit events#

An OpenAPI operation is a question and an answer in one exchange. An event has neither shape: nobody asked, the receiver did not choose the moment, and the interesting facts are the envelope, the delivery guarantee and the signature rather than a status code. Describing a webhook as though it were a request the receiver serves gets you an accurate path and none of what a receiver actually needs.

AsyncAPI names the pieces directly. A channel is where messages flow. An operation says whether this application sends or receives on that channel. A message carries headers, a payload schema and examples. Version 3.1.0 makes the send/receive direction explicit rather than leaving a reader to infer it, which matters when the same document describes both sides of a system.

Does Connect use AsyncAPI?#

Yes, as a publisher, and the scope is deliberately one thing. The document describes outbound webhooks: Connect notifying a subscribing system that a conversation was answered, a follow-up fell due, or something needs a person. One channel, workspaceEvents, whose address is the HTTPS endpoint the workspace registered; one operation, receiveEvent, which Connect sends by HTTP POST; one message envelope.

PartContents
Bodyid, type, occurredAt, workspaceId and a data object
X-Connect-Signaturesha256= and the hex HMAC-SHA256 of <timestamp>.<raw body>
X-Connect-TimestampUnix seconds at signing — reject anything far from now
X-Connect-EventThe event type, mirrored from the body so a receiver can route without parsing
X-Connect-DeliveryAttempt identifier; changes on each retry, unlike id

Delivery is at-least-once. The id is stable across retries and the delivery identifier is not, which is the pair a receiver needs: de-duplicate on id, log the delivery identifier when something goes wrong. A receiver that treats every POST as a new event will double-count the first time a network hiccup causes a retry.

What is not in this document is as deliberate as what is. Inbound provider callbacks — a carrier posting a call event, a mailbox push, a messaging webhook — are the application's own inbound surface. They are authenticated by provider signature, their shapes change with the provider, and they are not a developer API. Describing them here would invite integration against something nobody promised to keep stable.

Verifying an event before you trust it#

  1. Read the raw body as bytes. Do not parse it yet.

    Result You still have exactly what was signed. Re-serialising JSON changes bytes and breaks the comparison.

  2. Recompute the HMAC-SHA256 over <timestamp>.<raw body> with the subscription secret and compare in constant time.

    Result A mismatch means the request did not come from Connect, whatever the body claims.

  3. Reject a timestamp more than a few minutes from now.

    Result Replay is bounded. A valid signature on an old body is still an old body.

  4. Look up id. If you have seen it, acknowledge and stop.

    Result At-least-once delivery becomes effectively-once processing, which is the property your database actually needs.

When AsyncAPI is worth the file#

  • More than one message type. With a dozen event types and a shared envelope, a description is cheaper than a page of prose per type.
  • Receivers you do not control. Somebody else's team needs the schema, the headers and the retry semantics in a form their tooling reads.
  • A schema that is generated. If the envelope is derived from code, the description can be too, and the two cannot drift.
  • Not for a single internal callback. One provider webhook with one shape does not need a specification file; it needs a sentence and a signature check.

Connect's document is on the first three counts and pointedly not on the fourth, which is why the internal provider callbacks are excluded.

Questions#

Does AsyncAPI replace OpenAPI?

No; they describe different halves. OpenAPI covers the calls a client makes; AsyncAPI covers the messages that arrive unasked. A system with both an API and webhooks publishes both, and Connect does.

Is the webhook signature the same as the API's authentication?

No. API authentication proves who is calling Connect. A webhook signature proves that a request arriving at *your* endpoint came from Connect. They point in opposite directions and use different secrets — see Verifying a Connect webhook signature.

Should I use webhooks or poll?

Webhooks when you need to react promptly and can host a public HTTPS endpoint that verifies a signature; polling when you cannot. The trade-off is set out in Webhooks or polling.