Zahlo’s documentation is written to be read by coding agents. Give your agent the docs and a Sandbox key, and it can build a working integration.

Files for agents

  • /llms.txt: an index of every page with a one-line description. Start here.
  • /llms-full.txt: every page in one file, for agents that read everything up front.

Copy-paste prompt

Put your Sandbox secret key (it starts with zk_test_) in the environment variable ZAHLO_API_KEY, then give your agent this prompt, filling in the brackets:

Rules for generated integrations

  1. The secret key stays on the server. Read it from ZAHLO_API_KEY. The browser only ever gets a session’s url (hosted) or its clientToken (embedded).
  2. Verify every webhook on the raw request body before parsing it, and reject a bad signature or a timestamp more than 300 seconds old with 400.
  3. Dedupe and act in one transaction. Insert the event id into a table with a unique constraint and apply the business change (mark the order paid, grant access) in the same database transaction; return 2xx only after it commits. A duplicate event id returns 200 without work. Never record the event id, return 200, and fulfil afterwards: a crash in between loses the order.
  4. Tolerate out-of-order events. Re-fetch the object (GET /checkout-sessions/:id, GET /subscriptions/:id) and act on its current state instead of applying an older event’s data.
  5. Fulfil one-time orders on checkout.session.completed, never on payment.confirmed alone and never because the customer reached your success page. The success page shows “processing” until the webhook has run.
  6. Grant SaaS access from the subscription’s status: active while trialing or active, or past_due within the grace period.
  7. Handle reversals: refund.succeeded, dispute.created, subscription.payment_failed, subscription.past_due and subscription.cancelled.
  8. Retry safely. Send one Idempotency-Key per logical operation and reuse it on every retry. Retry only on a network error, 409 request_in_progress, 429 or a 5xx (including provider_outcome_unknown), at most twice, honouring Retry-After. Never retry other 4xx, and never retry with a new key.
  9. Never hard-code object ids. The Sandbox and live are separate accounts with different ids. Find prices with GET /prices?lookupKey=… and coupons by their code, and create customers at runtime. Treat every id as an opaque string.
  10. Register your checkout domains (POST /checkout-domains) before testing; in the Sandbox this includes localhost:<port>.
  11. Use {CHECKOUT_SESSION_ID} in successUrl so your success page can retrieve the session with the secret key.
  12. Check Not supported and Limits before promising a feature.