(03) Receber pagamentos
Sessões de checkout
Criar a sessão, mandar o comprador para o checkout, e o que volta.
Criar a sessão
Uma sessão de checkout é uma compra à espera de ser paga: o valor, a moeda, o que se paga, e para onde o comprador volta. Cria-se do teu servidor, no momento em que o comprador carrega em "Pagar" na tua loja.
curl -s "$SPOLLY_API_URL/v1/checkout/sessions" \
-H "Authorization: Bearer $SPOLLY_SECRET_KEY" \
-H "Idempotency-Key: encomenda-1042" \
-H "Content-Type: application/json" \
-d '{
"amount": 1500000,
"currency": "AOA",
"description": "Vestido de capulana",
"success_url": "https://loja.exemplo.ao/obrigado?pedido=1042",
"cancel_url": "https://loja.exemplo.ao/carrinho",
"metadata": {"order_id": "1042"},
"customer": {"email": "comprador@exemplo.ao"}
}'A resposta é 201 com a sessão. O que interessa é o url: redireciona o browser do comprador para lá (um 303 do teu servidor, ou um link).
{
"id": "cs_test_4f8Gk2LmQ9rT1vXz7bN3cH6sW0pY5aDe",
"object": "checkout_session",
"mode": "test",
"status": "open",
"url": "https://checkout.payments.spolly.ao/cs_test_4f8Gk2LmQ9rT1vXz7bN3cH6sW0pY5aDe",
"amount": {"amount": 1500000, "currency": "AOA"},
"description": "Vestido de capulana",
"line_items": [],
"payment_methods": ["mcx", "reference", "baipaga", "card"],
"success_url": "https://loja.exemplo.ao/obrigado?pedido=1042",
"cancel_url": "https://loja.exemplo.ao/carrinho",
"metadata": {"order_id": "1042"},
"customer": {"email": "comprador@exemplo.ao", "name": "", "phone": ""},
"expires_at": "2026-11-30T10:15:00Z",
"created_at": "2026-11-29T10:15:00Z",
"completed_at": null,
"payment": null
}Guarda o id da sessão com a encomenda
É por ele (ou pelos teus metadata, que voltam em todos os eventos) que ligas o webhook payment.succeeded à encomenda certa. O id é também a chave que abre o checkout: não o publiques.
Os campos do pedido
| Campo | Obrigatório | O que é |
|---|---|---|
amount | Sim | O valor, em unidades menores inteiras. Em AOA, múltiplo de 100 (os gateways angolanos cobram kwanzas inteiros). |
currency | Sim | AOA, USD ou EUR. USD e EUR só pelo cartão. |
description | Sem linhas, sim | O que o comprador vê que está a pagar, até 500 carateres. |
line_items | Não | Até 100 linhas com description, unit_amount e quantity; têm de somar amount. |
payment_methods | Não | Os métodos a oferecer: mcx, reference, baipaga, card. Sem ele, todos os que existem para a moeda. |
success_url | Não | Para onde o comprador volta depois de pagar, com session_id acrescentado (ou no lugar de {CHECKOUT_SESSION_ID}, se o escreveres no endereço). Sem ele, o checkout mostra a confirmação da Spolly. |
cancel_url | Não | Para onde volta se desistir, também com session_id. |
metadata | Não | Até 50 pares chave e valor teus (chave até 40 carateres, valor até 500), devolvidos tal como vieram na sessão e nos eventos. |
customer | Não | email (para o email da referência e para o recibo), name, phone (telemóvel angolano). |
expires_in | Não | A vida da sessão em segundos, de 900 a 86400. Por omissão, 24 horas. |
Os endereços de regresso são https:// em produção; em teste também aceitam http://. Um campo que não existe é recusado (400 pedido_invalido), para um nome mal escrito não passar em silêncio. A lista completa, com os tipos, está na referência.
Com linhas, só dois métodos, e uma hora para pagar
{
"amount": 2300000,
"currency": "AOA",
"line_items": [
{"description": "Camisa de linho", "unit_amount": 900000, "quantity": 2},
{"description": "Entrega em Luanda", "unit_amount": 500000, "quantity": 1}
],
"payment_methods": ["mcx", "reference"],
"expires_in": 3600
}Os estados da sessão
| status | Quer dizer |
|---|---|
open | À espera de pagamento. O comprador pode tentar várias vezes, com métodos diferentes. |
complete | Paga. payment traz o id do pagamento (pay_...), o método e status: succeeded. |
expired | O prazo (expires_at) passou sem pagamento. Envia-se checkout.session.expired. |
Uma tentativa recusada não fecha a sessão: o comprador pode tentar outra vez, e tu recebes payment.failed por cada tentativa que falha. Uma referência emitida no checkout deixa de se poder pagar quando a sessão expira, e nunca depois.
Ler a sessão
curl -s "$SPOLLY_API_URL/v1/checkout/sessions/cs_test_..." \
-H "Authorization: Bearer $SPOLLY_SECRET_KEY"Antes de responder, a API pergunta ao gateway pelos pagamentos que estão pendentes, por isso o estado que volta é o mais recente que existe. É o que a tua página de agradecimento chama para mostrar "pago" ou "a confirmar"; quem marca a encomenda como paga é o webhook. Ver Confirmar o pagamento.