Everything here is implemented in one runnable file:
sdk/examples/reference-merchant/server.ts.
Read that alongside this page — it is the same four steps, in the same order.What you are building
Alyte lets a buyer’s AI agent purchase from your shop within limits the buyer set. Three facts shape every integration decision, so they are worth reading once before writing code:- Your API token cannot spend. There is no merchant-side endpoint that charges a buyer. You hand off; the buyer approves in their own session. This is structural, not a permission you can be granted.
- Money settles to your own PSP. Alyte never holds your funds.
- A refused purchase is usually refused before any payment exists. That shapes how you diagnose problems — see step 4.
Step 1 · Hand off to the buyer
There is no API call here. You send the buyer to their authorize page:Step 2 · Receive the purchase
Register a webhook endpoint, then verify a delivery before a real sale depends on it:
Verify this step: the test delivery reaches your handler and verifies.
Step 3 · Fulfil exactly once
Two rules. Fulfil ontierId and quantity — never by matching the amount back to a
price. Prices change, and two tiers can cost the same.
Own your idempotency. Deliveries are at-least-once: we retry until we see a
2xx, so your handler can run twice for one sale — most often when it succeeded
but the response never reached us.
The SDK deliberately does not dedupe for you, because it cannot do it safely.
The dangerous window is inside your own process: issue the ticket and crash
before recording “handled” and a retry double-issues; record first and crash and
the buyer paid for nothing. Only your database closes that window, by writing
both facts in one transaction:
event.eventId, which is stable across retries — never on event.id,
which is the delivery id and changes every attempt.
Verify this step: send the same delivery twice; you should issue one ticket.
Step 4 · Diagnose it yourself
When a buyer says “my agent didn’t buy”, start here:deliveries — every webhook attempt with its status and error.
Two things this answers that nothing else does:
- Refusals with no payment to look up. The spend cap is checked before a
payment intent is created, so
spend_cap_exceeded, a quantity guardrail, a dead card,sale_endedandagent_goneall produce a failed watch and no intent id. This is the entry point that always works. - “Did the webhook reach me?”
deliveriesdistinguishes we never sent it from your endpoint rejected it — checkstatus,attemptsandlastErrorbefore suspecting your own code.
merchantFulfilment and buyerNotified always read unknown, on purpose. We
record webhook delivery, never whether you issued a ticket — we won’t claim
knowledge we don’t have.GET /v1/integration/payments/{intentId}
returns the same delivery history plus the reverse link to the watch.
You’re done
That is a complete integration. From here:- Lifecycle — every state a purchase can be in, and how to tell the recurring support cases apart
- Inventory and fulfilment — stock, holds, and why oversell is impossible
- Webhooks — retries, secret rotation, event reference
- Errors — the typed taxonomy and which codes are retryable
- Conversational shopfront — if a chat assistant is doing the hand-off

