Paylor
Sign in

Paylor API

One API, two environments. The key tells the environment; the id gives itself away; the order closes on the webhook.

Authentication

Every call carries Authorization: Bearer sk_live_… or sk_test_… (the secret key, only on your server). Older pk_… keys keep working until 2026-12-27: rotate them in the dashboard. The test key only sees the test world. Idempotency-Key is required in practice on everything that creates: repeating returns the same response; a different body with the same key is 409.

Authorization: Bearer sk_test_…
Idempotency-Key: <id do seu lado>
Accept-Language: pt-BR | en | es
Content-Type: application/json

Sellers

The seller comes with two pending fields. pendencia is the partner requirement as the partner writes it, in English: it is for logs and support, never for a screen. pendenciaChave is the Paylor key (documento_de_identidade, conta_bancaria, em_analise, desconhecida and others): that is the one you translate and show to the merchant. Both are null when nothing is missing. tipo_fiscal says what the store sells, for the sales tax added to the price when a sale is taxed; an order can send a different one just for itself. Values: servico_digital, servico_geral, servico_profissional, consultoria, contabilidade, juridico, saude, limpeza_residencial, limpeza_comercial, reparo_de_imovel, reparo_de_bem, instalacao, paisagismo, treinamento_presencial. Without it, servico_digital.

  • POST /v1/sellers
  • GET /v1/sellers
  • GET /v1/sellers/{id}
  • PATCH /v1/sellers/{id} { id_no_cliente?, tipo_fiscal? }
  • POST /v1/sellers/{id}/pause
  • POST /v1/sellers/{id}/resume
  • POST /v1/sellers/{id}/debits
POST https://paylor.io/v1/sellers
{ "nome": "Mira Studio", "nome_na_fatura": "Mira Studio", "email_do_dono": "ana@mirastudio.com",
  "moeda": "USD", "taxa": { "percentual_bps": 470, "fixo_centavos": 45 }, "plano": "Crescimento",
  "id_no_cliente": "loja_mira", "idioma": "pt-BR", "pais": "US", "volta_para": "https://…/access?order={id}",
  "tipo_fiscal": "servico_digital" }

201 { "id": "vend_test_…", "estado": "cadastro_pendente", "podeCobrar": false, "podeReceber": false,
  "pendencia": null, "pendenciaChave": null, "urlDoConnect": "https://paylor.io/connect/t_…" }

Orders

  • POST /v1/orders
  • GET /v1/orders?seller=&status=&buyer=&limit=
  • GET /v1/orders/{id}
  • POST /v1/orders/{id}/refunds
  • GET /v1/orders/{id}/refunds
POST https://paylor.io/v1/orders
{ "vendedor": "vend_test_…", "valor": 4900, "descricao": "Pack de presets Lightroom",
  "comprador": { "email": "miguel@exemplo.com", "idioma": "pt-BR" }, "reembolso_ate_dias": 7,
  "tipo": "unico" | "assinatura", "intervalo": "mes" | "ano", "id_no_cliente": "ped_7f31", "metadados": { } }

201 { "id": "PL-TEST-00012", "estado": "criado", "taxa": 275, "repasse": 4625, "checkoutUrl": "https://paylor.io/c/t_…" }

# preço em cada moeda (o checkout cobra na do país do comprador; não identificado: USD)
{ "vendedor": "vend_…", "valores": { "USD": 2900, "BRL": 14900 }, "descricao": "Plano" }
# com "moeda" junto, a moeda mandada vence o país do comprador (o preço que a sua tela mostrou)
{ "vendedor": "vend_…", "valores": { "USD": 2900, "BRL": 14900 }, "moeda": "BRL", "descricao": "Plano" }

# itens e de quem é cada um (a comissão só nos itens do vendedor); tipo_fiscal no item quando ele difere do pedido
{ "vendedor": "vend_…", "descricao": "Proposta", "itens": [
  { "descricao": "Site", "valor": 6000, "de_quem": "vendedor" },
  { "descricao": "Domínio", "valor": 4000, "de_quem": "plataforma", "tipo_fiscal": "servico_digital" } ] }

# guardar o cartão e, depois, cobrar de novo sem o comprador
{ "vendedor": "vend_…", "valor": 47760, "descricao": "Plano 24 meses", "guardar_cartao": true }
# em real, pago por Pix: a renovação sai pelo Pix Automático (mandato mensal até o valor da compra)
{ "vendedor": "vend_…", "valor": 47760, "descricao": "Renovação", "pagar_com": { "cartao_guardado_de": "PL-2026-00118" } }
402 { "erro": "CARTAO_PEDE_AUTENTICACAO", "detalhe": { "pedidoId": "…", "checkoutUrl": "…" } }

# só cartão (o checkout não oferece Pix): "meios": ["cartao"]; lista fechada: "cartao", "pix" (Pix só em real)
{ "vendedor": "vend_…", "valor": 50000, "moeda": "BRL", "descricao": "Site", "guardar_cartao": true, "meios": ["cartao"] }

# abrir a assinatura com o cartão guardado, sem o comprador: cobra agora, as próximas no mesmo dia de cada período
{ "vendedor": "vend_…", "valor": 15000, "moeda": "BRL", "descricao": "Gestão de redes", "tipo": "assinatura", "intervalo": "mes",
  "id_no_cliente": "gestao:42", "pagar_com": { "cartao_guardado_de": "PL-2026-00118" } }
201 { "tipo": "assinatura", "assinaturaId": "ass_…", "cobranca": "enviada" }   # assinatura.paga pelo webhook, com o mesmo assinaturaId
# o mesmo id_no_cliente de novo: { "cobranca": "existente" }, sem cobrar; recusa ou confirmação: 402 com o checkoutUrl, e a assinatura não nasce

POST /v1/orders/PL-TEST-00012/refunds  { "valor": 2450, "motivo": "…" }   (sem valor = total)
POST /v1/orders/PL-TEST-00012/refunds  { "item": 1, "motivo": "…" }   (um item inteiro; o mesmo item só uma vez: ITEM_JA_REEMBOLSADO)

Platform commission

Every account can be a platform. Your account's own store (the one you opened in the dashboard, marked propria: true) is born receiving commissions, one per world, test and live; turn it off or back on in Developers or through the API. Set how much you take from each connected store, in basis points (1500 = 15%). A sale splits in three: the Paylor fee, your commission on the sale amount, and the rest to the seller. The commission goes into your store's balance and is paid out with its payouts; on a refund it is reversed in proportion. Without a receiving store, turning on a commission is refused with COMISSAO_SEM_RECEBEDOR. Disputes come out of the seller's balance. On an order, comissao_centavos caps the commission at an amount (in the order's currency) for that sale and for every charge of the subscription: the lower of that amount and the store's percentage applies, never more. It does not combine with valores in several currencies.

  • POST /v1/sellers/{id}/commission-recipient
  • DELETE /v1/sellers/{id}/commission-recipient
  • POST /v1/sellers/{id}/commission { comissao_bps }
POST https://paylor.io/v1/sellers/vend_test_sua_loja/commission-recipient

POST https://paylor.io/v1/sellers
{ "nome": "Freela Zé", "email_do_dono": "ze@freela.com", "moeda": "USD", "pais": "US",
  "taxa": { "percentual_bps": 470, "fixo_centavos": 45 }, "comissao_bps": 1500 }

# venda de 100.00: { "taxa": 515, "comissao": 1500, "repasse": 7985 }

# teto em valor, num pedido ou numa assinatura
POST https://paylor.io/v1/orders
{ "vendedor": "vend_…", "valor": 60000, "descricao": "Honorário", "tipo": "assinatura", "comissao_centavos": 2500 }
# { "comissao": 2500, "comissaoPedida": 2500 }   15% daria 9000; vale o menor

Catalog and minimum fee

Each method's price is the provider's cost plus Paylor's margin. A store has a single fee for all methods in its currency, so the minimum is the most expensive method's; below it, store creation is refused with TAXA_ABAIXO_DO_CUSTO. An order in another currency uses the store's fee with the fixed part converted, never below that currency's minimum.

  • GET /v1/catalog
GET https://paylor.io/v1/catalog

200 { "margem": { "percentualBps": 180, "fixoCentavos": 15, "moeda": "USD" },
  "meios": [ { "meio": "pix", "moeda": "BRL", "custo": { … }, "preco": { "percentualBps": 630, "fixoCentavos": 15 }, "moedaDoFixo": "USD" }, … ],
  "minimos": { "USD": { "percentualBps": 470, "fixoCentavos": 45 }, "BRL": { "percentualBps": 720, "fixoCentavos": 234 } } }

Coupons

A coupon for one store or for the whole account (no seller). The buyer enters it at checkout, or you send it with the order. The discount comes off the price: fee, commission and payout are calculated on the discounted amount. At 100% a one-time sale closes with no charge at all. On subscriptions, duracao says for how long: uma_vez, meses (with duracao_meses) or sempre. With items, the discount is split in proportion to each item. A use counts when the payment goes through. Everything here is also in the dashboard, under Coupons.

  • POST /v1/coupons
  • GET /v1/coupons?seller=
  • GET /v1/coupons/{id}
  • DELETE /v1/coupons/{id}
  • POST /v1/orders { cupom }
POST https://paylor.io/v1/coupons
{ "codigo": "BLACKFRIDAY", "vendedor": "vend_…", "percentual_bps": 2000, "valido_ate": "2026-11-30T23:59:59Z", "max_usos": 500, "duracao": "meses", "duracao_meses": 3 }
# sem "vendedor": vale em todas as lojas da sua conta; valor fixo: "valor": 500, "moeda": "USD"
201 { "id": "cup_…", "codigo": "BLACKFRIDAY", "escopo": "loja", "usos": 0, "ativo": true }

POST https://paylor.io/v1/orders  { "vendedor": "vend_…", "valor": 10000, "descricao": "Curso", "cupom": "blackfriday" }
201 { "valor": 8000, "cupom": { "codigo": "BLACKFRIDAY", "desconto": 2000, "valorCheio": 10000 }, "taxa": … }
422 { "erro": "CUPOM_INVALIDO", "detalhe": { "motivo": "vencido" } }   # nao_existe, vencido, esgotado, ja_usado, minimo, abaixo_do_minimo, nao_vale_aqui
# 100%: o pedido fecha pago sem cobrança e sem taxa (pedido.pago com "valor": 0)

Pre-authorization

With manual capture the amount is held on the card (cards only) and the platform captures after the service, up to the held amount, or releases it. The deadline is the one the bank gives (autorizacaoExpiraEm); we warn 24 h before (pedido.autorizacao_expirando) and an expired hold becomes pedido.autorizacao_expirada. Fee, commission and payout come from the captured amount. With a saved card, hold at most 4 days ahead.

  • POST /v1/orders { captura: "manual" }
  • POST /v1/orders/{id}/capture { valor? }
  • POST /v1/orders/{id}/cancel { motivo }
  • POST /v1/orders/{id}/seller { vendedor, comissao_bps? }
  • POST /v1/payment-methods
  • GET /v1/payment-methods/{id}
POST https://paylor.io/v1/orders
{ "vendedor": "vend_…", "valor": 12000, "descricao": "Visita", "captura": "manual", "comprador": { "email": "…" } }
# o comprador autoriza no checkout: pedido.autorizado { "estado": "autorizado", "autorizado": 12000, "autorizacaoExpiraEm": "…" }

POST https://paylor.io/v1/orders/PL-2026-00140/capture  { "valor": 11000 }
200 { "estado": "autorizado", "valor": 11000, "resultado": "enviada" }   # pedido.pago pelo webhook

POST https://paylor.io/v1/orders/PL-2026-00141/cancel  { "motivo": "cliente desmarcou" }

# o prestador aceitou depois da reserva: o pedido segurado passa para a loja dele antes da captura
POST https://paylor.io/v1/orders/PL-2026-00140/seller  { "vendedor": "vend_…", "comissao_bps": 4000 }
200 { "vendedorId": "vend_…", "taxa": 515, "comissao": 4000, "repasse": 5485 }   # pedido.vendedor_trocado pelo webhook
# o cartão guardado vale em qualquer loja da mesma plataforma (gorjeta na loja do prestador, "comissao_bps": 0)

# visita longe: guardar o cartão sem cobrar, segurar 2 dias antes
POST https://paylor.io/v1/payment-methods  { "vendedor": "vend_…", "comprador": { "email": "…" } }
201 { "id": "cg_…", "estado": "pendente", "checkoutUrl": "https://paylor.io/save-card/…" }   # cartao.guardado pelo webhook
{ "vendedor": "vend_…", "valor": 12000, "descricao": "Visita", "captura": "manual", "pagar_com": { "cartao_guardado_de": "cg_…" } }

Payment methods

Each buyer has a wallet in your account: the cards they saved (in a purchase with guardar_cartao, in a subscription or on the save page) and, in reais, the Pix Automático authorization. One card is the default. Changing the default changes the card of every active subscription that person has in your account. The default only leaves after another becomes default, and one an active subscription uses cannot be removed. Pix Automático never becomes default: it only covers the purchase that created it, at its amount and rhythm. Expiry comes as month and year. The buyer sees and changes all of this on their own in the Paylor portal. No other account ever sees this wallet.

  • GET /v1/payment-methods?buyer=
  • GET /v1/payment-methods/{id}
  • POST /v1/payment-methods/{id}/default
  • DELETE /v1/payment-methods/{id}
  • POST /v1/orders { pagar_com: { principal_de } }
GET https://paylor.io/v1/payment-methods?buyer=ana@exemplo.com

200 { "dados": [
  { "id": "fp_…", "tipo": "cartao", "principal": true, "cartao": { "bandeira": "visa", "final": "4242", "validade": { "mes": 8, "ano": 2029 } } },
  { "id": "fp_…", "tipo": "pix_automatico", "principal": false, "pixAutomatico": { "valorMaximo": 24900, "moeda": "BRL", "periodicidade": "mes" } } ] }

# adicionar: a mesma página de sempre, e cartao.guardado chega com "formaDePagamento"
POST https://paylor.io/v1/payment-methods  { "vendedor": "vend_…", "comprador": { "email": "ana@exemplo.com" } }

POST https://paylor.io/v1/payment-methods/fp_%E2%80%A6/default
200 { "principal": true, "assinaturasTrocadas": ["ass_…"], "assinaturasNaoTrocadas": [] }   # forma_de_pagamento.principal_trocada

DELETE https://paylor.io/v1/payment-methods/fp_%E2%80%A6
200 { "id": "fp_…", "removida": true }   # cartao.removido
409 { "erro": "FORMA_PRINCIPAL" }   # escolha outra principal antes
409 { "erro": "FORMA_EM_USO", "detalhe": { "assinaturas": ["ass_…"] } }

# cobrar a principal, sem o comprador
POST https://paylor.io/v1/orders  { "vendedor": "vend_…", "valor": 4900, "descricao": "Renovação", "pagar_com": { "principal_de": "ana@exemplo.com" } }

Embedded fields (paylor.js)

The card is typed into a Paylor field inside your site: the number never touches your site or your server. Create the browser key (pub_) in the dashboard, under Developers, and register the sites where it works. The pmt_ token lasts 30 minutes, works once, and only with your secret key, on your server. When the response is requer_acao, call paylor.confirm with the id: the bank challenge opens inside the fields. Save a card without charging by sending the token to /v1/payment-methods. With integrity, the version is pinned; breaking changes go to /v2.

  • <script src="https://elements.paylor.io/js/v1/paylor.js">
  • POST /v1/orders { pagar_com: { token: "pmt_…" } }
  • POST /v1/payment-methods { token: "pmt_…" }
<script src="https://elements.paylor.io/js/v1/paylor.js"
        integrity="sha384-LSP7HKOOUU/QEnyf4R3eztbqymDUStY2oDIUywR9SM/1U53VLO/rEBUzgT1qpHWt" crossorigin="anonymous"></script>
<div id="card"></div>
<script>
  const paylor = Paylor("pub_test_…", { locale: "en" });
  const card = paylor.fields({ theme: { cor: "#0a7", raio: 10 } }).mount("#card");
  card.on("ready", () => {}).on("change", (e) => {}).on("error", (e) => {});
  // ao reservar:
  const { token, card: c, error } = await paylor.tokenize();   // pmt_… (30 min, uso único)
  // no seu servidor, com a chave secreta:
  //   POST https://paylor.io/v1/orders  { "vendedor": "vend_…", "valor": 12000, "captura": "manual", "pagar_com": { "token": "pmt_…" } }
  //   201 { "resultado": "enviada" | "requer_acao", … }
  // se "requer_acao" (o banco pede confirmação):
  const r = await paylor.confirm("PL-2026-00140");   // { confirmed: true }
</script>

Content-Security-Policy do seu site:
  script-src https://elements.paylor.io
  frame-src https://elements.paylor.io

Subscriptions

  • GET /v1/subscriptions/{id}
  • POST /v1/subscriptions/{id}/cancel { quando: agora | fim_do_periodo }
  • POST /v1/subscriptions/{id}/pause
  • POST /v1/subscriptions/{id}/resume

Disputes

  • POST /v1/disputes/{id}/evidence { provas: { entrega: '…', download: '…', termos: '…' } }

Webhooks back to you

Paylor POSTs to the client's URL with the paylor-assinatura header (t=unix,v1=hmac-sha256 of 't.body'). Reply 200. Five attempts: 1 min, 5 min, 30 min, 2 h, 6 h. After that the event waits in the admin and you can fetch it with GET /v1/events.

pedido.pagopedido.recusadopedido.expiradopedido.autorizadopedido.autorizacao_expirandopedido.autorizacao_expiradapedido.canceladopedido.vendedor_trocadocartao.guardadocartao.removidoforma_de_pagamento.principal_trocadaassinatura.pagaassinatura.falhouassinatura.pausadaassinatura.retomadaassinatura.canceladaassinatura.mandato_revogadoreembolso.feitoreembolso.falhoudisputa.abertadisputa.encerradarepasse.feitorepasse.falhourepasse.retidorepasse.a_pagardeposito.pagodeposito.falhouvendedor.atualizadowebhook.teste
GET /v1/events?after=evt_…&type=pedido.pago
GET /v1/events/{id}

{ "id": "evt_test_…", "tipo": "pedido.pago", "ambiente": "test", "criadoEm": "…", "objeto": { "tipo": "pedido", "id": "PL-TEST-00012" }, "dados": { … } }

Errors

Every error has a fixed code and a status. The code is never translated; the message is for the log.

NAO_AUTORIZADO 401PROIBIDO 403NAO_ENCONTRADO 404INVALIDO 400AMBIENTE_ERRADO 400VENDEDOR_NAO_APTO 409TRANSICAO_INVALIDA 409IDEMPOTENCIA_CONFLITO 409MOEDA_SEM_GATEWAY 409CATEGORIA_RECUSADA 403TAXA_ABAIXO_DO_CUSTO 422MOEDA_NAO_RECEBIDA_NO_PAIS 422COMISSAO_SEM_RECEBEDOR 409CARTAO_GUARDADO_AUSENTE 409FORMA_PRINCIPAL 409FORMA_EM_USO 409PIX_NAO_VIRA_PRINCIPAL 409CARTAO_PEDE_AUTENTICACAO 402CARTAO_RECUSADO 402AUTORIZACAO_VENCIDA 409CAPTURA_RECUSADA 402CUPOM_INVALIDO 422ITEM_JA_REEMBOLSADO 409TOKEN_INVALIDO 409ORIGEM_NAO_PERMITIDA 403DESAFIO_NECESSARIO 429CAMBIO_DA_VENDA_INDISPONIVEL 409CAMBIO_NAO_CONFIGURADO 503LIMITE_EXCEDIDO 429GATEWAY_NAO_CONFIGURADO 503PIX_NAO_CONFIGURADO 503