Environments
Two environments, one base URL, one integration. Which environment you are in is decided by the key you send — nothing else changes, so the code you test is the code that runs.
Base URL#
https://api.avvio.xyz/business/api/v1Every path in this documentation is relative to it.
Environments#
| Sandbox | Production | |
|---|---|---|
| Key prefix | akid_test_… |
akid_live_… |
| Base URL | _the same_ | _the same_ |
| Organization id in the path | _the same_ | _the same_ |
| Money | Simulated | Real |
| Settlement | Seconds | Hours to days, per corridor |
| Rates | Fixed and repeatable | Live, and they move between quoting and sending |
There is no separate hostname to configure and no environment flag to pass. A test key addresses the same organization id as your live key and resolves, server-side, to that organization's sandbox. Which means the only difference between your staging deployment and your production one is the value of two environment variables:
export AVVIO_API_KEY=akid_test_… # or akid_live_…
export AVVIO_PRIVATE_KEY="$(cat avvio-sandbox.pem)" # the matching private halfThe environment is derived from the prefix you present, never from stored state — so a key that reads akid_test_ in your logs cannot move real money, whatever else is true.
Your sandbox pair and your live pair are different pairs. Generate each in the dashboard when you issue that key; we only ever receive the public half.
What sandbox actually does#
Sandbox runs the real API — the same validation, the same corridor rules, the same error types, the same webhooks. What it does not do is touch a payment network:
Balances are yours to set. Fund your sandbox organization from the dashboard; no transfer is made and no bank is contacted.
Payouts settle in seconds, walking the same states a live payout walks:
pending → processing → completed.Rates are fixed, so a quote you assert against today is the same quote next week. This is the one place sandbox deliberately lies — real rates move between quoting and sending, and Going live is about that.
Recipient validation is real. A CLABE with a bad check digit is rejected in sandbox exactly as it is in production, because that check is ours.
Production access#
Production keys are issued once your organization is verified. Nothing about the integration changes at that point: same base URL, same paths, same payloads. You swap two environment variables and the money becomes real — which is why the pre-production checklist is worth an hour before you do.
Versioning#
The version is in the path: v1.
Backwards-compatible changes ship continuously, without a version change. Treat all of these as expected, and build so they cannot break you:
- new endpoints
- new optional request parameters
- new fields in a response object
new values in an enum — including new error
typevalues, new payout states, and new corridors
Parse responses permissively: ignore fields you do not recognize, and never enumerate an error type in a way that throws on an unfamiliar one. Every error carries the two facts you need regardless of whether you know its name — whether your money moved, and whether retrying is safe. Errors is the table.
Breaking changes get a new version in the path. Removing a field, renaming one, changing a type, or making an optional parameter required will never happen to v1 in place.
Deprecation#
If we ever retire a version:
- We write to your organization's registered technical contact.
- The migration window is at least 90 days from that notice.
- The retiring version keeps working, unchanged, for the whole window.
- A changelog entry accompanies the notice.
We will not shorten a window for a live partner. If a security issue ever forced a faster change, you would hear from a human first, not from a 400.
Rate limits#
Ask before you build against an assumed ceiling — limits vary by route and partner traffic is bucketed per credential, with a separate source-IP abuse ceiling. We would rather raise yours than have you discover it in production. RATE_LIMITED is always safe to retry after the response's backoff interval.