Environments
An environment is the base URL a request goes to — which project's database and providers
it reaches. This is a different question from test mode (the sk_live_/sk_test_ key
prefix): see Test mode for what that prefix does and does not do yet. This page
answers only "where do I send the request".
Base URL
| Environment | Base URL | Status |
|---|---|---|
| Production | https://api.swaps.app/v1 | The only base URL this reference publishes. Each resource runs behind its own operator switch; while a resource's switch is off, its operations answer 503 temporarily_unavailable. |
| Development | Not published here | A separate, non-production project, with the Bridge sandbox behind it. Issued out of band, together with a development key, when the account team grants one — not self-service, and not covered by any availability commitment. |
There is exactly one server in the published OpenAPI contract (servers in the generated
reference). If you were handed a development base URL directly, it is a different host from the
one above — treat it as internal-use, not something to build a public integration against.
Hosted payer pages
A payment link's url opens the payer page of the project that holds the link:
| Project | Payer page | Who gets it |
|---|---|---|
| Production | https://swaps.app/pay/<token> | Live keys. A test key's link has no page here, so its url is null. |
| Development | https://staging.swaps.app/pay/<token> | Live and test keys on the development project. |
The host comes from each project's own configuration, not from the code. Until a project's host
is configured, url is null: no address is guessed, and a development link never gets a
production URL, where its token would not resolve.
Payer e-mails (invoice, reminder, payment nudge) do not read this setting yet: their /pay links
still follow the project's configured origin and can differ from url. Share url itself when the two
must match.
The /v1 path convention
The base URL already carries the version segment: production's base URL is
https://api.swaps.app/v1, so every path in the reference — /payment_links,
/capabilities, /account — is relative to it, never repeated. A full request URL is the base
URL followed directly by the path, e.g. https://api.swaps.app/v1/payment_links (see the
Get started quickstart for a runnable example).
Key prefix and environment
sk_live_… and sk_test_… are not something you choose per request — the prefix is fixed for a
given key at the moment it is issued, because it is fixed for the account the key belongs to:
every account carries its own livemode (set once, at creation), and a key can only be minted in
the mode that matches its account. This is enforced twice, not just documented: a database
trigger refuses to write an api_keys row whose mode disagrees with its account's livemode,
and the request-time auth check re-derives the expected mode from the account and compares it
again before honoring the key. A mismatch — a key that somehow disagrees with its own account — is
401 invalid_api_key, never a silent downgrade to the other mode and never a partial success.
Asking for a key in the other mode is resolved at issuance, not at use: from a live account,
POST /v1/api_keys with livemode: false mints the key on the account's test twin, creating the
twin the first time (see Test mode); from a test twin, livemode: true answers
400 mode_mismatch (param: mode).
Once the key authenticates, its account's mode — which the prefix always matches — decides how
the request runs. sk_live_… runs in production against live providers. sk_test_… runs as the
account's test twin, on the same base URL: API-key, request-log and account reads run in
production; webhook endpoints, webhook deliveries and the per-object event lists are forwarded to
the development project over a signed hop; and every other operation a key may call answers
503 temporarily_unavailable.
What the base URL does decide is where the key is looked up at all: a key is a row in one
project's database, so it authenticates only against the base URL of the project that issued it —
a development key sent to https://api.swaps.app/v1 fails authentication like any unknown key,
and a production key sent to a development base URL does the same. See
Test mode for exactly what is and is not implemented.
Next: Test mode for the key-prefix contract in full · Get started for a runnable request against the published base URL.