PaystationdocsPaystation

A API /v1 é a mesma em homologação e produção, cada uma no seu endereço (veja Ambientes e chaves). As requisições e as respostas são JSON.

Autenticação ​

Toda requisição leva a chave no cabeçalho Authorization:

bash
curl https://paystation.quero.space/v1/me -H "Authorization: Bearer sk_live_…"
  • A chave pública (pk_…) pode ir para o navegador e alcança só o que o checkout precisa.
  • A chave secreta (sk_…) fica no seu servidor e alcança todas as rotas.
  • Cada rota da referência diz qual chave aceita.

Valores em centavos ​

Todo valor de dinheiro entra e sai em centavos inteiros: R$ 99,90 é 9990.

Idempotência ​

POST /v1/charges exige o cabeçalho Idempotency-Key, um UUID v4 gerado por você para cada tentativa de compra. Se a resposta se perder, repita a requisição com a mesma chave e a mesma compra: a compra não é cobrada duas vezes. Só payment.cards pode mudar entre um envio e outro, para levar tokens de cartão ainda válidos.

bash
curl -X POST https://paystation.quero.space/v1/charges \
  -H "Authorization: Bearer sk_live_…" \
  -H "Idempotency-Key: 6b1f6d7e-3c2a-4e0b-9f4d-8a5c2e7b1d90" \
  -H "Content-Type: application/json" \
  -d '{ "offer_id": "…", "payment": { "method": "pix" }, "customer": { … } }'
  • A partir do momento em que a cobrança começa, a resposta fica guardada na chave, 402 card_declined e 422 payment_rejected inclusive, e a repetição a devolve com Idempotent-Replayed: true. Por isso, outro cartão depois de uma recusa é outra tentativa, com chave nova. A exceção é o 402 acquirer_disabled, que libera a chave: no primeiro envio ele quer dizer que nada foi cobrado; num reenvio, não diz nada sobre o envio anterior.
  • Um 5xx, 503 api_unavailable inclusive, é sempre resultado desconhecido: a cobrança pode ter sido feita. Repita a mesma chave.
  • Uma recusa antes de a cobrança começar (validação do corpo, Turnstile, oferta inexistente, limite de requisições) não guarda nada: a mesma chave pode ser enviada de novo, mas só dentro do limite de reenvio da regra de tentativa. Depois dele, uma chave livre ainda cobraria.
  • Enquanto a primeira requisição está rodando, a repetição recebe 409 idempotency_key_in_use. Se ela terminou sem resposta guardada, a repetição devolve o estado atual da cobrança, sem Idempotent-Replayed.
SituaçãoResposta
Sem a chave, ou fora do formato UUID v4422 missing_idempotency_key ou invalid_idempotency_key
A mesma chave ainda em processamento409 idempotency_key_in_use: repita mais tarde
A mesma chave com outro corpo: algo além de payment.cards mudou, inclusive a ordem das chaves do JSON409 idempotency_key_reuse: reenvie o corpo guardado; sem ele, procure a cobrança. Nunca troque a chave
Uma resposta guardada há mais de 24 horas409 idempotency_key_expired: a tentativa pode ter cobrado
Uma tentativa que parou no meio e não tem resposta a dar409 idempotency_key_unresolved: a tentativa pode ter cobrado

Nos dois últimos casos, não abra uma tentativa nova antes de procurar a cobrança pela chave. A regra completa, com a busca, está em Checkout próprio.

Turnstile ​

POST /v1/charges pode pedir o token do Cloudflare Turnstile resolvido pelo comprador, no cabeçalho cf-turnstile-token:

  • numa cobrança de cartão com a chave pública, sempre;
  • em qualquer cobrança, com qualquer chave, quando o cliente ativou o Turnstile.

Sem o token, a resposta é 403 turnstile_required; com um token recusado, 403 turnstile_invalid; com um token já usado vezes demais, 403 turnstile_budget_exhausted. Nos três casos, o comprador resolve o desafio de novo. O checkout embutido cuida disso sozinho.

Erros ​

Todo erro vem no mesmo envelope:

json
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_param",
    "message": "offer_id must be a uuid.",
    "param": "offer_id",
    "request_id": "req_2f9c0e4a-…"
  }
}
typeStatusSignifica
invalid_request_error422; 404 para o que não existe; 409 para um conflito, como upsell_already_purchased; 400 malformed_path para um caminho que não decodificaA requisição tem um problema. param diz onde.
authentication_error401Chave ausente, inválida ou do tipo errado.
permission_error403Falta o Turnstile, ou ele foi recusado.
rate_limit_error429Limite de requisições atingido.
idempotency_error409Conflito de Idempotency-Key.
card_error402O cartão foi recusado.
api_error500, ou 503 api_unavailableErro do lado do Paystation. Num 503, repita com a mesma Idempotency-Key: se a cobrança já tiver sido feita, a repetição devolve o resultado dela em vez de cobrar de novo.

Decida pelo code, não pela message, que pode mudar. As respostas da API trazem o cabeçalho X-Request-Id, o mesmo valor de request_id. Mande-o ao suporte para localizar a requisição.

Duas recusas vêm antes da API e não têm envelope nem X-Request-Id: 400 INVALID_PAYLOAD, quando o corpo não é um JSON válido, e 400 INVALID_QUERY, quando limit não é um número inteiro ou vem repetido.

Paginação ​

As listagens, como GET /v1/charges e GET /v1/offers, devolvem { data, has_more }, do mais novo para o mais antigo. Para a próxima página, passe o id do último item em starting_after:

bash
curl "https://paystation.quero.space/v1/charges?limit=100&starting_after=6f1c2b1e-…" \
  -H "Authorization: Bearer sk_live_…"

limit vai de 1 a 100 (padrão 20). Um parâmetro desconhecido ou repetido é recusado com 422, em vez de ser ignorado.

Limites ​

LimiteValor
Por chave600 requisições por minuto, somando as rotas
Por endereço IP2.000 requisições por minuto
GET /v1/charges/{id}1.200 por minuto por chave, à parte do limite por chave
POST /v1/charges com a chave pública10 a cada 15 minutos por chave e IP do comprador
POST /v1/charges com a chave secreta120 por minuto por chave

Ao passar de um limite, a resposta é 429 rate_limit_error. Espere e tente de novo com intervalo crescente. Para acompanhar um Pix ou boleto até o pagamento, consulte GET /v1/charges/{id} ou, melhor, espere o webhook.