Close the email loop: inbound parse, Flow reply, ticket
The outbound quickstart ends at a delivered message, and the inbound-routing guide ends at a parsed webhook. This tutorial stitches them into the loop a support address actually needs: a customer writes in, Orbit parses the mail on a managed route, a Flow sends an acknowledgement within seconds, and the thread opens as a ticket in the inbox for an agent to pick up. The SDK tabs below read the API key fromORBIT_API_KEY; cURL passes it as
X-API-Key. Where a route sits below an SDK’s typed helpers, the tab uses
that SDK’s escape hatch — orbit.request (Node.js), client.request
(Python and Ruby), client.Request (Go), $client->request (PHP) — the
same convention the Sandbox API cookbook
uses for untyped routes, per the
SDK sample coverage policy.
You will:
- See the loop you are about to build
- Baseline the outbound send
- Provision a receiving domain
- Register the inbound route
- Handle the inbound event with a Flow
- Read the thread as a ticket in the Inbox
- Debug the common failure modes
1. What you build
One work loop, end to end:- An outbound send establishes your verified sender and domain (two lines of cURL — the full sender verification is in Send your first transactional email).
- An inbound route rents an address the customer can write back to.
- A Flow reacts to the inbound event and replies “we got your message” without an agent touching anything.
- The same inbound mail opens a ticket in the Inbox, so an agent owns the follow-up.
2. Outbound baseline
Confirm the sender exists and mail goes out — this is the whole outbound side of the loop:data.succeeded non-empty is the signal to move on. Work
through Send your first transactional email
first if any of domain verification, sender registration, or template
rendering is still open — the inbound steps below assume that path is green.
3. Provision the receiving domain
Pick a dedicated subdomain (for exampleinbound.your-domain.com) so MX
routing for inbound parse does not compete with your corporate mail, and
point its MX records at Orbit’s ingress — the dashboard shows the hostname
under Email → Inbound routes → Add route. Any address at that domain
becomes a candidate for a route once DNS propagates. This is the same flow
as step 1 of Inbound email and SMS routing.
4. Register the inbound route
Register the destination pattern and webhook URL once:signingSecret exactly once —
store it now, because list and get responses mask it:
X-Orbit-Signature (sha256=<hex> HMAC over the raw request
body) on every forward — the full receiver pattern is in
Build a durable webhook consumer. A lightweight
receiver that verifies and returns 2xx quickly is all this step needs.
5. Handle the inbound event with a Flow
Inbound email route rules have no reply path themselves — the constraint is stated verbatim in the inbound-routing guide, and a Flow is its designated resolve. Subscribe to the inboundmessage.received event and compose the
acknowledgement:
channel: "email" filter prevents the ack Flow from answering SMS and
WhatsApp inbound too. This minimal form — event trigger, one send node — is
the whole loop; the Flows overview covers branches,
delays, and richer orchestration.
The inbound event the Flow’s {{from}} and {{subject}} templates read is
the same envelope your destinationUrl receives on every forward:
6. The thread lands in the Inbox
Every matched inbound email opens (or threads onto) an inbox ticket in parallel with the webhook forward — your Flow acknowledgement fires off the pipeline while an agent picks up the assigned work under Inbox. The ticket fields and the receive → reply pattern at the API level are in Send & Receive Messages. Keep the Flow reply short and factual; the agent reads the ticket and carries the conversation from there.7. Common failures
- Route never fires.
recipientPatternis matched against the SMTP envelope recipient first, then theToandCcheaders — but only when one of them names the address you registered. BCC-only mail, and mail whose envelope was rewritten upstream, both miss. Log the recipient your sending path actually used and match that — full matching rules are in Inbound email and SMS routing. - Signature mismatch.
X-Orbit-Signatureis HMAC over the raw request body — verifying a re-serialized JSON body always fails. Read the body as bytes before any framework middleware parses it; the pattern is in Build a durable webhook consumer. - Duplicate route rejected. Registering the same
recipientPatterntwice returns 409 CONFLICT on the second call — update the existing route withPATCHinstead of re-creating it. - Flow fires for every channel. The
filters.channelfield scopes the trigger — omit it and your ack reply answers SMS and WhatsApp inbound too. - Ticket never opens on a broken webhook. The ticket pipeline runs in
parallel with webhook forward — but only if a route actually matched.
If
GET /email/inbound-routesshows risingfailureCount, the match may still be firing; iflastFailureAtis empty and no ticket opens, re-check the pattern from the bullets above.