# API do Payflow — o que mudou

A versão da API vai no cabeçalho `Kingdom-Version` de cada resposta e no campo
`api_version` de cada webhook. Uma integração fica presa à versão com que foi
criada: mudanças que partem código só chegam a quem pedir a versão nova.

**O que nunca conta como mudança que parte código** — e por isso pode aparecer
sem versão nova: um campo novo num objecto, um tipo de evento novo (só chega a
quem o subscrever), um valor novo num `status`, um cabeçalho novo, um parâmetro
novo opcional. Escreva o seu código a ignorar o que não conhece.

---

## 2026-10-05 — o cartão nas assinaturas

Sem versão nova: um valor novo em `payment_method.type` e um campo novo.

- **`payment_method: {"type":"card"}`** em `POST /v1/subscriptions` (e em
  `POST /v1/subscriptions/{id}`), nos produtos de uma moeda que aceita cartão
  (hoje ZAR); noutra moeda dá `422 payment_method_currency`. Antes dava
  `payment_method_unavailable`.
- A primeira fatura (a validação, ou o primeiro período) paga-se na página dela
  (`hosted_invoice_url`, ou com o `payment_token` no checkout da Paystack), só
  por cartão: os outros canais do mercado não deixam um cartão que se possa
  voltar a cobrar. Paga com um cartão reutilizável, as faturas seguintes cobram-se
  sozinhas nesse cartão no dia em que vencem e nos dias de tentativa do produto
  (`retry_days`, contados a partir do vencimento). Uma recusa deixa a fatura
  aberta, com o link para pagar à mão.
- **`payment_method.card`** (`brand`, `last4`) na assinatura, depois de o cartão
  pagar uma fatura. O código do cartão nunca sai do Payflow.

## 2026-10-04 — assinaturas e faturas

Sem versão nova: são recursos, âmbitos, eventos e um campo novos.

- **`Product.recurring`** — nos produtos de assinatura (cobrança recorrente mensal,
  ciclo de 30 dias, ou anual, de 365), o ciclo e as regras: `setup_amount` (a
  validação cobrada à entrada e descontada na primeira fatura de período),
  `trial_days`, `invoice_days_before`, `retry_days` e `grace_days`. `null` nos
  outros produtos.
- **`POST /v1/subscriptions`** — `product`, `customer` (`email`, `name`, `phone`),
  `payment_method` (`{"type":"mpesa","phone":"84…"}`, só em MZN, ou
  `{"type":"manual"}`), `billing_details` e `metadata`. Devolve a assinatura
  (`sub_…`) com a `latest_invoice` aberta e o **`payment_token`** dela: o token
  público com que o browser de quem paga pede o PIN ao Payflow. A chave `sk_`
  nunca sai do seu servidor. O cartão chegou a 2026-10-05 (em cima).
- **`GET /v1/subscriptions`** (filtros `status`, `product`, `customer_email`,
  `created[gte|lte]`, `metadata[…]`) e **`GET /v1/subscriptions/{id}`**.
- **`POST /v1/subscriptions/{id}`** — muda `metadata` (junta-se à que há),
  `billing_details`, `payment_method` e `automatic_collection`.
- **`POST /v1/subscriptions/{id}/cancel`** — já, ou com `at_period_end: true` no
  fim do período pago; uma assinatura que já acabou dá `409 subscription_ended`.
- **`GET /v1/invoices`** (filtros `subscription`, `status`) e **`GET
  /v1/invoices/{id}`** (`in_…`): cada fatura é uma cobrança do Payflow, com o
  número do documento, a página pública (`hosted_invoice_url`) e o pedido que
  gerou quando é paga.
- Estados da assinatura: `incomplete`, `trialing`, `active`, `past_due`, `unpaid`,
  `canceled`, `incomplete_expired`. Da fatura: `open`, `paid`, `void`.
- Âmbitos novos: `subscriptions:read`, `subscriptions:write`, `invoices:read`.
- **Eventos novos**, só para quem os pedir em `enabled_events`:
  `subscription.created`, `subscription.updated` (com `previous_status`),
  `subscription.canceled`, `invoice.created`, `invoice.paid`, `invoice.voided`.
  Cada um traz `data.subscription` e, os de fatura, `data.invoice`.
- Uma fatura de uma assinatura criada com uma chave `sk_test_` não se paga pelo
  M-Pesa: marca-se paga no painel.
- JSON Schema: `Subscription.json`, `Invoice.json` e um por evento novo.

## 2026-09-27 — `data.attribution` nos eventos de pedido

Sem versão nova: é um campo novo num objecto.

- **`data.attribution`** — de onde veio a venda, em todos os eventos de pedido
  (`order.paid`, `order.refunded`, `order.disputed`, `order.dispute_resolved`).
  Duas chaves, sempre presentes: `first_touch` (a primeira visita da pessoa com
  origem conhecida) e `last_touch` (a visita que pagou), cada uma `null` quando
  não se sabe.
- Cada toque pode trazer `source`, `medium`, `campaign`, `content`, `term` (os
  UTM), `fbclid`, `ttclid`, `gclid`, `referrer`, `landing_page` e `at`. A página
  e o referrer vêm sem a query: o que lá houver de pessoal não sai daqui.
- A segunda parcela de uma venda leva a origem da venda.
- Pedidos anteriores a esta data trazem `{"first_touch": null, "last_touch": null}`.
- JSON Schema: `Attribution` e `Touch`, dentro de `Event.order.paid.json` e dos outros.

## 2026-09-26 — `deal.stage_changed`

Sem versão nova: é um tipo de evento novo, e só chega a quem o pedir.

- **`deal.stage_changed`** — uma oportunidade nasceu ou mudou de etapa no quadro
  do Payflow. `data.deal` traz o `id` (`opp_…`), a `stage` e a
  `previous_stage` (`opportunity`, `proposal_sent`, `negotiating`, `won`,
  `lost`, `archived`; `null` quando nasce), o valor em subunidades, a moeda, o
  `product_id`, a `expected_close_date`, o `owner`, o
  `lost_reason` (só em `lost`) e a `source` (`manual`, `tracktor`, `migracao`).
  `data.customer` é o mesmo objecto dos eventos de pedido.
- **`won` só pelo pagamento.** Uma oportunidade passa a `won` quando o primeiro
  pagamento da inscrição dela é confirmado, e esse evento traz o `order_id` do
  pedido. Nenhuma pessoa a marca como ganha à mão.
- Não faz parte dos eventos por omissão: uma integração criada sem escolher
  eventos continua a receber só os quatro de pedido. Para o receber, inclua-o em
  `enabled_events`.
- JSON Schema: `Event.deal.stage_changed.json`.

## 2026-09-01 — a primeira

**API** em `https://api.kingdomcompny.com/v1`, especificada em
[`openapi.json`](https://payflow.kingdomcompny.com/api/openapi.json) (OpenAPI 3.1).

- Autenticação com `Authorization: Bearer sk_live_…` ou `sk_test_…`. Uma chave
  de teste só vê o modo de teste. Âmbitos por chave; IPs opcionais.
- Recursos: `products`, `orders`, `customers`, `events`, `refunds`,
  `checkout_sessions`, `webhook_endpoints` — listar (cursor com
  `starting_after`, `limit` de 1 a 100) e obter por id.
- Escrever: `POST /v1/checkout_sessions`, `POST /v1/checkout_sessions/{id}/expire`,
  `POST /v1/refunds`, e criar, mudar, apagar, rodar o segredo e testar
  `webhook_endpoints`.
- `Idempotency-Key` em todos os `POST` e `PATCH` (24 horas; a mesma chave com
  outro corpo é recusada com 409).
- Erros em `application/problem+json` (RFC 9457), sempre com `code` e `request_id`.
- `Request-Id` em todas as respostas; `RateLimit-Limit`, `RateLimit-Remaining`,
  `RateLimit-Reset` — 300 pedidos por minuto por chave.
- Valores em **subunidades** da moeda (R 149,00 = `14900`).
- Sem CORS: uma chave secreta não se usa a partir de um browser.

**Webhooks** — `order.paid`, `order.refunded`, `order.disputed`,
`order.dispute_resolved`, `integration.test`.

- Duas assinaturas em cada entrega: `X-Kingdom-Signature` (`t=…,v1=<hex>`) e a
  do Standard Webhooks (`webhook-id`, `webhook-timestamp`, `webhook-signature`).
- Rotação de segredo com 24 horas em que seguem as duas assinaturas.
- Oito tentativas ao longo de ~45 horas; ordem garantida por pedido.
- JSON Schema de cada evento em
  `https://payflow.kingdomcompny.com/api/schemas/<Tipo>.json`
  (por exemplo `Event.order.paid.json`).

**Link de compra** — `https://payflow.kingdomcompny.com/p/prod_…` com `email`,
`name`, `locale`, `ref` e `return_url`; os outros parâmetros vão para
`metadata`. O regresso acrescenta `status` (`success`, `failed`, `cancelled`) e
`reference`.
