> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userkit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Importando assinaturas

> Adote as assinaturas que seu gateway já está cobrando — e as quatro coisas que a adoção se recusa a adivinhar.

Seus clientes já vêm pagando em algum lugar há um tempo. Conectar o gateway não
traz ninguém para cá sozinho, e esta página explica por quê, e o que fazer a
respeito.

## Por que elas não chegam sozinhas

Toda assinatura que este sistema guarda é um **espelho** de uma do seu gateway,
e o jeito comum de uma linha existir é um checkout iniciado aqui: a linha nasce
primeiro, o id dela viaja até o gateway como referência do checkout, e é o
checkout concluído que amarra os dois.

Uma assinatura criada antes disso tudo — anos atrás, ou semana passada no painel
da própria Stripe — nunca passou por essa porta. Os webhooks dela chegam, sim, e
são guardados, e terminam com uma nota dizendo que nada aqui está ligado a
`sub_…`. O que está certo: a resposta de um gateway nomeia um pagador que o
gateway inventou, e **qual dos seus times é esse** não é algo que ele possa
dizer.

Essa é a única peça que falta, e é aqui que você a fornece.

## Faça o catálogo primeiro

Uma assinatura adotada precisa de um plano, e o plano é resolvido a partir do
preço em que ela é cobrada — então o preço do gateway precisa estar mapeado no
seu catálogo antes que a assinatura possa ser adotada. Se você ainda não fez
isso:

```bash theme={null}
curl -X POST "$API/v1/organization/environments/$ENV/billing-providers/stripe/catalogue-import" \
  -H "Authorization: Bearer $UK_SESSION" \
  -H "X-Organization-Id: $ORG"
```

Isso lê os produtos e preços do seu gateway e escreve planos e preços aqui, com
o mapeamento. Se você precificou seu produto aqui primeiro, publique seus preços
no gateway — mesmo mapeamento, direção oposta.

Garanta também que o **health check** da conexão já rodou pelo menos uma vez. Um
mapeamento de preço é chaveado pela conta de comerciante, e a conta só é
conhecida depois que alguém perguntou ao gateway a quem as chaves pertencem.

## Depois dê os recursos a esses planos

**É este o passo que fica de fora**, e ele falha calado. A importação traz
planos e preços, e mais nada — nenhum recurso, nenhuma matriz. Um gateway sabe o
que ele cobra; ele não faz ideia do que o seu produto deixa alguém fazer.

Então uma assinatura adotada num plano importado resolve para um plano **sem
recurso nenhum**: o cliente está no Pro, paga o Pro, e não tem direito a nada.
Nada dá erro, e o primeiro relato disso é um chamado no suporte.

Configure os recursos de cada plano antes de adotar qualquer coisa — no painel,
em Catálogo, ou pela API do catálogo. Se você já adotou, arrumar o plano arruma
todas as assinaturas que apontam para ele: os entitlements resolvem pelo plano,
não por uma cópia tirada na hora da adoção.

## Adotando uma

```bash theme={null}
curl -X POST "$API/v1/organization/subscriptions/link?environment=live" \
  -H "Authorization: Bearer $UK_SESSION" \
  -H "X-Organization-Id: $ORG" \
  -H "Content-Type: application/json" \
  -d '{
        "customer_external_id": "acme-inc",
        "provider_subscription_id": "sub_1P9x…"
      }'
```

```json theme={null}
{
  "id": "3d90…",
  "customer_id": "6f1c…",
  "plan_id": "b271…",
  "status": "active",
  "current_period_start": "2026-08-30T00:00:00Z",
  "current_period_end": "2026-09-30T00:00:00Z",
  "provider": "stripe",
  "provider_subscription_id": "sub_1P9x…",
  "provider_synced_at": "2026-09-09T15:04:05Z",
  "mirror_refreshed": true
}
```

**201** quer dizer que agora existe uma linha que não existia.

Nada nessa resposta veio do seu pedido além do cliente. O status, o período, o
trial, um cancelamento agendado e a quantidade da linha são todos lidos do
gateway; o plano vem do mapeamento de preço. Nada foi cobrado e nada mudou no
gateway — o que mudou é que este sistema agora guarda a assinatura.

Dali em diante ela se comporta como qualquer outra: os webhooks a encontram, a
reconciliação noturna a relê, os entitlements resolvem pelo plano dela, e ela
pode ser alterada ou cancelada por aqui.

## Nomeando o cliente

Por `customer_id`, ou por `customer_external_id` — o **seu** id para o time, que
é o que torna isso scriptável: seu backend já sabe qual conta corresponde a qual
`cus_`, e não deveria ter que guardar um mapa dos nossos uuids também. Mande um
ou outro; um pedido com os dois carrega duas convicções sobre quem está pagando.

O cliente precisa existir. Este endpoint não cria um, porque um time conjurado
para pendurar dinheiro seria um time sem membros — use `POST /v1/customers` na
superfície de máquina, que é a chamada que sabe o nome do time.

## Rodando sobre uma lista

Uma migração de qualquer tamanho é um script, então o mesmo ato está na
superfície de máquina, sob uma chave `uk_sk_` — onde o ambiente é o **da chave**
e nenhum campo o move:

```bash theme={null}
curl -X POST "$API/v1/subscriptions/link" \
  -H "Authorization: Bearer $UK_SECRET_KEY" \
  -H "Idempotency-Key: backfill-$EXTERNAL_ID" \
  -H "Content-Type: application/json" \
  -d "{\"customer_external_id\": \"$EXTERNAL_ID\", \"provider_subscription_id\": \"$SUB\"}"
```

Duas camadas respondem a duas repetições diferentes, e vale saber qual é qual:

* a **`Idempotency-Key`** repete a mesma resposta, bytes e status, para uma
  requisição repetida — é disso que o backoff de um cliente precisa, e é o que
  impede uma resposta perdida de virar uma segunda chamada;
* adotar a **mesma assinatura para o mesmo cliente** de novo, sob uma chave
  nova, responde **200** com a linha e não escreve nada — é disso que uma
  re-execução do lote uma semana depois precisa.

A mesma assinatura para um cliente **diferente** é recusada dos dois jeitos: é a
única repetição que significa que alguém errou.

Ou seja: um script que morre no meio pode simplesmente ser rodado de novo. Leia
o seu próprio mapa de conta para `cus_`, resolva as assinaturas de cada uma no
gateway, e chame isto uma vez por linha — as recusas abaixo dizem quais linhas
olhar, e o resto está feito.

## O que ela se recusa a adivinhar

Não existe desadotar. Uma assinatura nunca é apagada aqui, e a referência do
gateway só é escrita em uma coluna vazia — então um vínculo errado é permanente,
e tudo que teria que ser presumido é recusado no lugar.

| Código                         | O que aconteceu                                                                                                    | O reparo                                                                                   |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `price_not_mapped_to_provider` | O preço em que ela é cobrada não está no seu catálogo, então não há plano para registrá-la                         | Importe o catálogo. A resposta traz `unmapped_provider_price_id` — é esse o preço a mapear |
| `subscription_has_extra_items` | O gateway guarda mais de uma linha cobrada, e qual delas nomeia o plano não é pergunta que gateway nenhum responda | Espelhe essa à mão, ou simplifique no gateway                                              |
| `subscription_already_linked`  | Ela já está espelhada aqui, sob outro cliente                                                                      | Confira qual cliente você quis dizer                                                       |
| `customer_mismatch`            | O gateway diz que quem paga é um pagador diferente daquele com que esse cliente vem pagando                        | Quase sempre uma linha trocada em algum script                                             |
| `provider_account_unknown`     | A conexão nunca foi verificada, então a conta de comerciante é desconhecida                                        | Rode o health check da conexão                                                             |

`customer_mismatch` só dispara quando há com o que comparar. Não guardamos
`cus_` nenhum, então a referência de pagador de um cliente é descoberta lendo
uma assinatura que ele já tem — e um cliente que você está prestes a migrar
normalmente não tem nenhuma. Silêncio não é divergência, e recusar por causa
dele recusaria a migração inteira.

## O que ela não faz por você

**Não encontra as assinaturas.** Não existe um "importar tudo" aqui, e isso é
deliberado: a qual time cada `sub_` pertence é o único fato que este sistema não
consegue derivar, e um endpoint em lote teria que adivinhá-lo para todas as
linhas de uma vez. Seu backend tem o mapa; esta é a chamada que o registra.

**Não traz as faturas antigas.** O que é adotado é a assinatura e o estado atual
dela. Os pagamentos feitos antes de ela existir aqui ficaram no gateway, que
continua sendo onde esse histórico vive; as faturas do próximo pagamento em
diante chegam por webhook como sempre.

## Por último: aponte o webhook do gateway para cá

A adoção registra a assinatura **como ela está agora**. Tudo o que vier depois —
uma renovação, um pagamento que falha, um cancelamento, uma troca de plano feita
no gateway — chega por webhook, e só se o gateway souber para onde mandar.

O endereço está na tela do provedor de pagamento, no painel, em **URL do
webhook**, assim que a conexão existe. Cole no painel do seu gateway e guarde o
segredo de assinatura aqui.

Pule este passo e tudo o que você acabou de migrar congela no estado em que
chegou, sem nada indicando isso. Uma assinatura cancelada no mês passado
continua lendo como ativa, e o cliente continua com o acesso.
