A valid request URL is required to generate request examples{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "incomplete",
"current_period_start": "2023-11-07T05:31:56Z",
"current_period_end": "2023-11-07T05:31:56Z",
"cancel_at_period_end": true,
"canceled_at": "2023-11-07T05:31:56Z",
"trial_ends_at": "2023-11-07T05:31:56Z",
"provider": "stripe",
"provider_account_id": "<string>",
"provider_subscription_id": "<string>",
"provider_synced_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"items": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 123,
"price": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"kind": "recurring",
"currency": "<string>",
"amount_minor": 123,
"tax_behavior": "inclusive",
"archived": true
}
}
],
"capabilities": {
"scheduled_plan_change": true,
"proration": true,
"cancel_at_period_end": true,
"hosted_portal": true,
"tax_calculation": true,
"resume_subscription": true,
"list_invoices": true,
"list_catalogue": true,
"publish_catalogue": true,
"manage_coupons": true,
"pause_subscription": true,
"discount_subscription": true,
"refund_payment": true
},
"mirror_refreshed": true,
"mirror_stale_reason": "provider_reread_failed",
"unmapped_provider_price_id": "<string>"
}{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "incomplete",
"current_period_start": "2023-11-07T05:31:56Z",
"current_period_end": "2023-11-07T05:31:56Z",
"cancel_at_period_end": true,
"canceled_at": "2023-11-07T05:31:56Z",
"trial_ends_at": "2023-11-07T05:31:56Z",
"provider": "stripe",
"provider_account_id": "<string>",
"provider_subscription_id": "<string>",
"provider_synced_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"items": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 123,
"price": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"kind": "recurring",
"currency": "<string>",
"amount_minor": 123,
"tax_behavior": "inclusive",
"archived": true
}
}
],
"capabilities": {
"scheduled_plan_change": true,
"proration": true,
"cancel_at_period_end": true,
"hosted_portal": true,
"tax_calculation": true,
"resume_subscription": true,
"list_invoices": true,
"list_catalogue": true,
"publish_catalogue": true,
"manage_coupons": true,
"pause_subscription": true,
"discount_subscription": true,
"refund_payment": true
},
"mirror_refreshed": true,
"mirror_stale_reason": "provider_reread_failed",
"unmapped_provider_price_id": "<string>"
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Adopt an existing subscription
Records a subscription that already exists at your gateway and has never existed here, in the environment your key names. The migration path for arriving with customers who are already paying — and the reason it belongs on a key rather than only in the panel is that your backend is the only system that holds the map from a gateway payer to one of your accounts.
It is the same act as the panel’s, with the same refusals. See the guide for the order to do things in: connect the gateway, import the catalogue, give the plans their features, make sure the teams exist, then run this over your list.
What it does
Reads the subscription from the gateway and writes it down against the customer you name — status, period, trial, scheduled cancellation and line. Nothing is charged, nothing is created at the gateway, and nothing about the subscription changes: what changes is that this system now holds it. From then on webhooks find it, the nightly reconciliation re-reads it, and entitlements resolve through its plan.
Naming the customer
By customer_external_id — your own id for the team — or by customer_id. Send exactly one. The customer has to exist; this does not create one, and POST /v1/customers is the call that does.
Running it over a list
Two layers answer two different retries. The surface’s Idempotency-Key replays the same response for a repeated request, which is what a client’s backoff needs. And adopting the same subscription for the same customer again answers 200 with the row and writes nothing, which is what a batch re-run a week later needs. Adopting it for a different customer is refused: that is the one repeat that means somebody made a mistake.
A 201 means a row now exists that did not.
What it refuses to guess
There is no un-adopt — a subscription is never deleted here, and its gateway reference is only ever written into an empty column — so anything that would have to be assumed is refused: a price that is not mapped into this environment’s catalogue (there is no plan to record it against), a subscription the gateway holds several priced lines for (which line names the plan is a question no gateway answers), one this environment already mirrors, and one the gateway says a different payer holds.
That last check runs only on evidence. No gateway customer id is stored here, so this customer’s payer reference is discovered by reading a subscription they already hold — and a customer you are about to migrate usually has none. Silence is not a mismatch.
A valid request URL is required to generate request examples{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "incomplete",
"current_period_start": "2023-11-07T05:31:56Z",
"current_period_end": "2023-11-07T05:31:56Z",
"cancel_at_period_end": true,
"canceled_at": "2023-11-07T05:31:56Z",
"trial_ends_at": "2023-11-07T05:31:56Z",
"provider": "stripe",
"provider_account_id": "<string>",
"provider_subscription_id": "<string>",
"provider_synced_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"items": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 123,
"price": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"kind": "recurring",
"currency": "<string>",
"amount_minor": 123,
"tax_behavior": "inclusive",
"archived": true
}
}
],
"capabilities": {
"scheduled_plan_change": true,
"proration": true,
"cancel_at_period_end": true,
"hosted_portal": true,
"tax_calculation": true,
"resume_subscription": true,
"list_invoices": true,
"list_catalogue": true,
"publish_catalogue": true,
"manage_coupons": true,
"pause_subscription": true,
"discount_subscription": true,
"refund_payment": true
},
"mirror_refreshed": true,
"mirror_stale_reason": "provider_reread_failed",
"unmapped_provider_price_id": "<string>"
}{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "incomplete",
"current_period_start": "2023-11-07T05:31:56Z",
"current_period_end": "2023-11-07T05:31:56Z",
"cancel_at_period_end": true,
"canceled_at": "2023-11-07T05:31:56Z",
"trial_ends_at": "2023-11-07T05:31:56Z",
"provider": "stripe",
"provider_account_id": "<string>",
"provider_subscription_id": "<string>",
"provider_synced_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"items": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 123,
"price": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"kind": "recurring",
"currency": "<string>",
"amount_minor": 123,
"tax_behavior": "inclusive",
"archived": true
}
}
],
"capabilities": {
"scheduled_plan_change": true,
"proration": true,
"cancel_at_period_end": true,
"hosted_portal": true,
"tax_calculation": true,
"resume_subscription": true,
"list_invoices": true,
"list_catalogue": true,
"publish_catalogue": true,
"manage_coupons": true,
"pause_subscription": true,
"discount_subscription": true,
"refund_payment": true
},
"mirror_refreshed": true,
"mirror_stale_reason": "provider_reread_failed",
"unmapped_provider_price_id": "<string>"
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Autorizações
An organization API key, uk_sk_live_… or uk_sk_test_…. The environment is resolved from the stored key row on every request, never from a request parameter.
Every route behind this credential is rate limited per key — 1000 requests a minute — with a second ceiling of 3000 a minute across all the keys of one environment, so splitting your traffic across keys isolates it and minting more keys does not buy more of it. A test key can never spend a live key's allowance. Every response carries the current state in headers; see the rate-limits guide.
Cabeçalhos
A key you choose — a UUID, or your own identifier for the operation — that makes this write safe to retry. Send the same key again and you get the same response back: the same status, the same body, and Idempotent-Replay: true. The handler does not run a second time.
The key is scoped to your API key and the route, so keys never collide between environments or tenants. It is remembered for 24 hours. Reusing it for a different request is refused (422), and a second request arriving while the first is still running is refused too (409) — retry that one in a moment.
A request that failed with a 5xx or was rate limited leaves the key spendable: retry it with the same key.
255Corpo
The gateway's own id for the subscription to adopt, such as a Stripe sub_….
Your own id for the team that is paying. Mutually exclusive with customer_id.
The same, addressed by our id. Mutually exclusive with customer_external_id.
Which gateway holds it. Only needed when the environment has more than one connected.
stripe Resposta
It was already adopted for this customer, and the row is returned unchanged. Nothing was written.
What one of your customers is paying, mirrored from the gateway.
That word decides how to read every field below. The gateway is the source of truth about money; this is a local copy kept so an entitlement can be answered without a network call, joined to the rest of your data, and read while the gateway is unreachable. provider_synced_at is when the copy was last confirmed — null means never, which is what a checkout that was started and not completed looks like.
Who is billed. A subscription always hangs off a customer, including when that customer is a team of one.
What they are subscribed to, as opposed to how it is billed — which is items. Entitlements are computed from the plan's features, so this always has exactly one answer.
In our vocabulary, never a gateway's spelling, so this does not change when you change gateway.
incomplete is created and not yet paid — no access. past_due is paid before and a payment has failed; whether that keeps access is a grace-period decision and not this field's. unknown means the adapter did not recognise what the gateway said: it is a reason to look, never a reason to charge anybody or to cut them off, and it deliberately does not read as active or as canceled.
incomplete, trialing, active, past_due, paused, canceled, unknown The period paid for. Null together with the end, never one alone: an incomplete subscription has no period, and a made-up one is a date an entitlement expires on that nothing happens at.
A cancellation that has been scheduled and has not happened. The subscription is still active until current_period_end, which is why this is its own field rather than a status.
When it actually stopped. Null while it has not.
Null when there is no trial — which is a different fact from a trial that ended, and only one of them should make a screen say a trial expired.
Which gateway holds this subscription. Exactly one: that is who is charging the card.
stripe The merchant account, as the gateway names it. Empty until a health check has asked who the keys belong to.
The gateway's own id. Empty for a checkout that was started and never completed — a row that exists here and nowhere else, and the one state in which no act on this subscription is possible.
When this copy was last re-read from the gateway, as opposed to when the row was last written. Null means never confirmed. A mirror that cannot say how stale it is would be claiming to be the source.
The lines. Present on a single subscription, absent from the list.
Show child attributes
Show child attributes
What a gateway can do beyond the minimum every gateway can do. Every flag defaults to false, so a provider that declares nothing is treated as the weakest one — silence is never a claim. Read it to stop offering an act that would be refused.
Every flag below is always present. The object is emitted whole or not at all: absent means this server has no adapter loaded for the gateway, and it never means "some flags were left out". A reader must therefore distinguish false from missing rather than testing for falsiness — a key that is not here is not a gateway that cannot do something, it is a question nobody asked.
Show child attributes
Show child attributes
Present only on the answer to an act. true means the gateway was re-read afterwards and everything above is what it said. false means the act happened and the copy above is not (or not entirely) the gateway's answer — either the re-read did not get through, or it did and part of it could not be written down. mirror_stale_reason says which. Treat it as a reason to read again, never as a sign the act failed.
Present whenever mirror_refreshed is, and null when it is true — an absent field would leave you inferring that nothing is wrong.
provider_reread_failed — the gateway was not reachable after it accepted the act. Nothing above was updated; read again.
price_not_mapped_to_provider — the gateway named a price that is not mapped onto any price in this catalogue for this environment, so plan_id was left as it was while everything else was applied. This one matters: entitlements are computed from the plan, so until you map the price (see unmapped_provider_price_id) the customer keeps the plan they were on. Prices created in the gateway's own dashboard are the usual cause.
subscription_has_extra_lines — the gateway holds more priced lines than one, so which of them names the plan is not decidable and both plan_id and items were left as they were.
provider_reread_failed, price_not_mapped_to_provider, subscription_has_extra_lines, null The gateway's own price id to map, when mirror_stale_reason is price_not_mapped_to_provider. Null otherwise.