Skip to main content
The SDK implements this protocol for you. Read this page if you build an app in another language, or if you need the exact requests and responses to debug raw deliveries.

One endpoint

Reintersect sends every delivery as an HTTPS POST to one URL: your app’s endpoint for self-hosted apps, or the path /reintersect of your Worker for hosted apps. The SDK treats any request with reintersect-delivery and webhook-signature headers as a delivery. Each request carries Standard Webhooks headers plus two of its own: Verify the signature and reject timestamps more than 5 minutes from your clock before you parse the body. See Webhooks and security.

Envelope

Every body has the same envelope. type says which delivery it is, and data holds its payload:

Interactive deliveries

Interactive deliveries happen while someone waits, for example when a member clicks a button, pastes a link, opens a search tab, runs a slash command or picks a message action. You have 5 seconds to answer, or 30 seconds for command.run and messageAction.run. Reintersect never retries an interactive delivery. If your app fails or times out, the block keeps its last good tree and shows an inline error, and a command or message action shows the member a failure card. Answer 200 with the result in the table below, or 202 to finish later (see Deferred results and Commands and message actions). tallies on block.action maps each viewer input to its counts, such as { verdict: { go: 4, nogo: 1 } }. invocationId is unique per click. input holds form values, or the picks of a choice group’s onChange. A response that doesn’t match the result schema fails the call with ReintersectAppResponseInvalidError on Reintersect’s side, and Reintersect refuses responses over 1 MB. In block.insert, target.circleId is set when the block goes into a circle, and target.conversationId when its message is filed in a conversation. Neither is set for a block outside a circle, such as a playground preview. The delivery never carries replyTo: an API insert with replyTo arrives with that reply’s circle, plus its conversation when it has one.

Action result

Every field is optional:
For an action whose manifest hint is readOnly, Reintersect ignores state, tree, actions, final and notify. The SDK merges partial state from your handler before it answers, so the wire state is always the full state.

Reference resolution

unavailable means the reference couldn’t be resolved right now. Reintersect doesn’t cache it and resolves again later. The SDK sends it when a resolve handler throws. externalId identifies the object: every occurrence of the same kind and externalId in a workspace shares one record, so one update reaches all of them. See Resolving references.

Deferred results

If an action needs more than a few seconds, answer 202 Accepted with an empty body, keep working, and push the result with the interactionToken from the delivery:
The interaction token is valid for 15 minutes and only for the block the delivery is about. While the block waits, the member sees the button’s pending state. See Update a block.

Commands and message actions

command.run and messageAction.run carry the run’s identity and where it happened:
options holds only the options the member filled in, already checked against your manifest. message.conversationId is null for a chat message not filed in a conversation and for a direct message. context.level is the level the install’s version declares; see Message actions for what each level sends. EventAuthor is described in the event catalog. Both answer 200 with an InvocationAnswer:
A danger or warning notice with no content or block reports the run as failed. Or answer 202 with an InvocationDeferral, and send the answer within 15 minutes to POST /v0/invocations/respond with the delivery’s interactionToken and your install token. See Slash commands for how Reintersect places each answer.
visibility decides who sees your app thinking while it works: everyone on the surface, or only the member who ran it. Any other body fails the run. The answer you send later has its own visibility.

Block trees

tree is a block-UI document: a JSON tree of catalog nodes, shaped like the documents Reintersect’s editor stores.
  • attrs.catalog is the catalog version. It’s 1 today.
  • attrs.summary is required plain text, at most 280 characters.
  • Node names start with ui. Rich text inside uiProse reuses the editor’s paragraph, heading, list, blockquote and codeBlock nodes.
  • The root’s children go uiHeader, the body, one uiActions, then uiFooter. A button bound to a destructive action carries "intent": "destructive" and a confirm of { title, body? }.
  • A metric’s value and its delta’s value are finite numbers, and the metric’s format says how to read them. Percent values are fractions: 0.08 is 8%.
  • Reintersect validates every tree against the catalog and the limits and rejects a tree that doesn’t pass.
Your output may use src image URLs and avatarSrc; Reintersect copies the images and stores asset ids instead. To check a tree against the same validator Reintersect runs, send it to POST /v0/apps/check/trees.

Action references

Buttons, menu items, forms and choice groups refer to actions by short references such as a0 and a1. The actions table you return with each tree maps every reference to an action name and its arguments:
Reintersect stores this table on its servers. Browsers only ever see the references, so a member can’t change the arguments by editing the request. When the member clicks, Reintersect looks up the reference for the tree’s revision and sends block.action with the stored name and arguments. References are unique within one tree revision and mean nothing outside it.

Lifecycle deliveries

Lifecycle deliveries report things that already happened, such as an install, a published decision or a mention of your app. Reintersect stores them in an outbox and retries them, so your handler can be slow or briefly unavailable.
  • Answer any 2xx within 15 seconds to acknowledge. The body is ignored.
  • Reintersect retries other responses and timeouts with jittered exponential backoff from one minute up to six hours, at most 20 attempts.
  • 410 Gone pauses deliveries to that install.
  • After three days of continuous failures, Reintersect pauses deliveries to the install and emails the app’s owner. The developer resumes them from the app’s Deliveries page.
  • Order isn’t guaranteed. Every object in a payload carries a version; ignore a delivery whose version is older than one you’ve already processed.
  • A delivery can arrive more than once. Use webhook-id to skip duplicates.
The type is one of the events in the event catalog.