Skip to main content
Going live is a configuration change, not a rewrite — provided the items below are already true. Each one is a thing that has broken a real integration on its first production day.

Credentials and environment

  • Production credentials issued, and separate from sandbox. A sandbox key does not work against production.
  • The base URL comes from configuration, not from a constant. Production is the same host without the /sandbox prefix, and that prefix applies to every path.
  • Credentials are not in your source tree. Environment variables or a secret manager, never a committed file.
  • The version header is sent on every request, with the same value everywhere.

Webhooks

  • Your production URL is registered, in the Developers section of the dashboard, subscribed to the events you handle.
  • Your endpoint answers quickly and acknowledges before doing work. A handler slower than 30 seconds is cut off; that counts as a transient failure and is retried, but the event arrives late.
  • Handlers are idempotent. The same event can arrive more than once, and must not pay anyone twice.
  • You answer 2xx to event names you do not recognise. A refusal is the one failure that is never retried.
  • You reconcile against a read, for anything where missing an event would be wrong. Retries stop after roughly 80 minutes.
  • You react to state changes rather than polling for them. Anything you poll for in production is latency you chose.

Money handling

  • Every create call sends an Idempotency-Key, a fresh UUID per operation and not per retry.
  • A 409 is handled as “already done”, not as a failure to retry with the same key.
  • Amounts are parsed as decimals, never as floats. They arrive as strings — "1000.00" — and a float will eventually round money.
  • from_amount and to_amount are expected to differ. The gap is fees and conversion, not a bug.
  • A price shown to your customer came from a lock that has not expired, or is presented as an estimate.

Failures

  • Your error handling does not read one field. The reason sits under message on some bodies and under error on others, so a handler that reads only one logs nothing useful for the rest.
  • You branch on the status code and on code, compared case-insensitively, and treat everything else as display text.
  • A 401 triggers a token refresh rather than a support ticket.
  • In-flight is a state you show, not one you resolve by guessing. A transfer is delivered when it says so and failed when it says so.

Compliance

  • Someone has dashboard access and knows they are the one who answers a request for information.
  • You surface missing_fields to whoever can collect it — usually your own customer, not your engineers.
  • Your flow tolerates a customer being held. Verification is not instant and can reopen later.

Before you flip

  • Run the full cycle in sandbox once more, on the code you are about to deploy rather than on the code you tested weeks ago.
  • Move one real payment first, small, and watch it land before opening the tap.
  • Know who to contact, and have the account id ready when you do.
If any box above is unchecked because the documentation did not answer it, that is a defect worth reporting rather than a gap to work around. Tell your Kira contact which one.