Flowyte → you
Signed webhooks to your
endpoint_url. You verify them with the signing secret
(whsec_…). This is the doorbell.You → Flowyte
REST calls to the Flowyte API. You authenticate with a scoped connector key
(
flowyte_sk_…). This is where the truth lives.Two different secrets, two different jobs. The signing secret only ever verifies inbound webhooks —
it is not an API credential. The connector key only ever authenticates your outbound REST calls — it
never appears in a webhook. Never swap them.
Before you start
- The API base URL. Every path in this guide —
/escalations,/escalations/{id}/messages— is relative tohttps://builder.flowyte.com/api/v1. SoPOST /escalationsisPOST https://builder.flowyte.com/api/v1/escalations. The MCP gateway, if you drive Flowyte that way instead, is a separate host:https://mcp.flowyte.com/mcp. - An AI Harness runtime you control, reachable at an absolute
https://URL. Flowyte SSRF-checks it: private, loopback and link-local targets are refused at registration and re-checked at send time. - A Flowyte organization with at least one agent.
- For the
smschannel: the organization’s A2P 10DLC (TCR) registration must be complete — the same registration its inbound number already needs. See SMS. - Starter or higher to run real conversations. Setup and the handshake test work on any plan, so you can wire everything up before upgrading.
1. Connect the harness integration
In the dashboard’s Integrations page, connect your AI Harness provider —hermes or openclaw (or
POST /integrations/{kind}/connect). This is enablement only: it stores no credential, it just marks
the provider connected for the organization.
Nothing else on this page works until you do. Every escalation surface re-checks this server-side, so
disconnecting the integration later immediately stops new conversations reaching your harness — it does
not merely hide a button.
2. Give Flowyte your endpoint URL
This is the one thing you hand Flowyte. Register a destination — the record that says where conversations go and which channels you handle.1
Create the destination
In Integrations → your harness → Add destination, give it a name, your
endpoint_url, and tick
the channels you handle (Chat, SMS, or both). Over the API this is
POST /escalation-destinations with escalation_destinations:write.Optional knobs: context profile (which handoff bundle you receive), transcript window (how
many recent turns come with it, default 20), claim window (how long Flowyte waits for you to
claim before falling back — default 120 seconds), and a fallback route.2
Copy the signing secret — it is shown once
The create response carries
signingSecret (whsec_…) exactly once. It is never returned by any
later read. Store it in your secret manager before you close the drawer; if you lose it, rotate it
(POST /escalation-destinations/{id}/rotate-secret) rather than hunting for it.unverified. The handshake test in step 5 is the only path to active — no
API call can set it directly.
3. Mint a connector key
In the dashboard’s Developer page, mint a secret key (flowyte_sk_…) for your harness. It is shown
once. Every REST call carries it:
The key is organization-scoped: it only ever sees its own tenant’s sessions, and a cross-tenant call
fails closed as
404. These scopes are deliberately separate from escalation_destinations:* — a
connector key can work conversations but cannot edit the destinations or agents it works for.
4. Verify webhook signatures
Flowyte signs every delivery. Verify before you do any work — parse nothing, queue nothing, and above all claim nothing on an unverified body.401 from you, and no work.
Rotation, concretely. After
rotate-secret, Flowyte sends Flowyte-Signature (new secret) and
Flowyte-Signature-Prev (previous secret) for 24 hours. A connector still holding only the old secret
keeps verifying, because its secret matches the -Prev header. Pick up the new secret inside that
window; after it, only the new secret verifies.2xx as delivered and gives you 10 seconds total.
Acknowledge immediately and process asynchronously. A non-2xx or a timeout is retried up to 6
attempts (immediately, then 30s, 1m, 2m, 4m, 8m) and then dead-lettered. Delivery is at-least-once,
so dedupe on Flowyte-Delivery.
5. Pass the handshake test
The go-live gate. In Integrations → your harness → Handshake test, hit Run test (orPOST /escalation-destinations/{id}/test). Flowyte opens a sandbox escalation on a synthetic
conversation, delivers a signed escalation.test webhook, and then waits for your connector to complete
the loop:
1
Verify the signature
Exactly as in step 4. Treat
escalation.test as identical to escalation.requested — same code
path, no special case.2
Claim
POST /escalations/{id}/claim. Retry on 409 and 404: a redelivered webhook can transiently
conflict, and the session may not be visible for a beat right after it is created. Claiming is
idempotent for your own key.3
Post one message
POST /escalations/{id}/messages with a client_message_id and text.4
Resolve
POST /escalations/{id}/resolve.{ webhook_delivered, claimed, message_posted, resolved } — plus a
verdict and, on failure, a hint naming the first step you missed (for example “Connector claimed the
session but posted no message within 120s. Check the escalations:respond scope on the connector key.”).
Both a pass and a fail come back as HTTP 200 — read
result, not the status code. Only a green run
flips the destination to active. A test message reaches no customer and is never billed; your
connector does not need to know that, and should not branch on test.tools/mock-connector (Go, stdlib only) as a working reference for this whole loop, with
a -fail-step flag to reproduce each failure hint.
6. Route real conversations to it
Set the agent’s escalation policy —PUT /agents/{id}/escalation-policy, or the Escalation policy
page — as an ordered list of rules: when to escalate and where to route. Conditions are
deterministic (an explicit request for a person, a human request, business hours, channel, a failed tool
or knowledge lookup); routes are external:<destinationId>, an email fallback, or a queue. First match
wins.
The policy edits the agent draft — publish it so live traffic uses
it.
From then on, the loop is:
escalation.requestedarrives. Verify, dedupe, claim.- Claim returns the context package: the recent transcript turns (each with its spine
seq), the escalation reason, verified identifiers (on SMS, the customer’s phone), and completed or failed tool actions. It is rebuilt at claim time, so you start current. - Reply with
POST /escalations/{id}/messages.client_message_idis your idempotency key — a replay returns the original receipt instead of double-sending. - Sync with
GET /escalations/{id}/messages?after_seq=Nand process strictly increasingseq. - Finish with
/resolve,/return(hand back to the Flowyte AI), or/request-human.
/messages read. Send /heartbeat if you go quiet but want to keep the
thread. If the lease expires the thread returns to the AI and you get 409 lease_expired; re-claim to
continue.
7. Start an outbound SMS thread (optional)
If your harness needs to open the conversation rather than wait for one,POST /escalations starts a new
SMS thread and sends its first message. The session comes back already owned by your key — no claim,
no SLA race — and the customer’s replies route to you exactly like any other escalation.
- Consent. The recipient must have a recorded basis. An inbound text is consent to text back — a
customer who has ever texted the business is already
conversationaland needs nothing extra. A number that has never texted in is refused422 consent_required. - It must be switched on. Outbound initiation is off by default and enabled per organization by
Flowyte, on top of the deployment-level Agent Bridge switch. Otherwise
403 harness_outbound_disabledor503 bridge_disabled. - There is no
from. The sending number is derived from the agent’s SMS-active number, and the agent must have one (422 no_sms_number). - Send the message only. The brand identity and the
Msg & data rates may apply. Reply HELP for help, STOP to opt out.block are appended for you on a first text. Writing your own ships it twice.
409 quiet_hours with a nextOpen instant to retry
after — never silently queued.
The full contract — every error code, the volume cap, the audited consent bypass, a worked end-to-end
example — is in the connector reference.
When it does not work
Next
- Connector reference — the full contract you keep open while building.
- AI Harnesses — the operator-side view of the same setup.
- MCP gateway — the same surface as agent tools, if your harness speaks MCP rather than REST.