Links de pagamento
Um Payment Link é uma página de checkout hospedada e compartilhável (URL com assinatura) para vender um ou mais itens. Você cria, consulta, lista, atualiza e remove links como um recurso persistente.
| Operação | Método | Endpoint |
|---|---|---|
| Criar | POST | /v1/checkouts/payment-links |
| Listar | GET | /v1/checkouts/payment-links |
| Consultar | GET | /v1/checkouts/payment-links/{paymentLinkId} |
| Atualizar | PUT | /v1/checkouts/payment-links/{paymentLinkId} |
| Excluir | DELETE | /v1/checkouts/payment-links/{paymentLinkId} |
Todas as requisições usam o header SelectKey (veja Autenticação).
O ID público de um link tem o prefixo link_.
Criar
POST /v1/checkouts/payment-links
curl -X POST "https://api.selectwin.io/v1/checkouts/payment-links" \
-H "SelectKey: sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ" \
-H "Content-Type: application/json" \
-d '{
"name": "Black Friday PIX",
"items": [ { "id": "var_01hqzvabc", "quantity": 1 } ],
"editable": false,
"expiresAt": "2026-12-31T23:59:59Z"
}'Campos da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
name | string | Sim | Nome de exibição (1–255 caracteres) |
items[] | array | Sim | Itens do link: { id, quantity } (1–100 itens). id é a variante (var_... ou prv_...); quantity é inteiro ≥ 1 (default 1, máx. 100000) |
discounts[] | array | Não | Códigos de cupom pré-aplicados (strings, 1–50 caracteres cada, máx. 20). A validação/retenção autoritativa acontece na cobrança |
customInputs[] | array | Não | Campos de formulário customizados (objetos livres, máx. 50) |
expiresAt | datetime | Não | A partir deste instante o link não pode mais ser usado |
availableAt | datetime | Não | Instante a partir do qual o link passa a valer |
editable | boolean | Não | Permite o cliente editar o carrinho na página (default false). Com false a trava vale no servidor (desde 15/09/2026): o autosave da sessão recusa trocar item, mudar quantidade ou adicionar linha (422 checkoutCartNotEditable); order bump e upsell seguem regra própria. Antes era só de tela, e o cupom do link passava a valer para qualquer carrinho. |
templateId | string | Não | Template de checkout (tmpl_... ou ckt_...). Não é só visual: o template define desconto por método, parcelas, endereço obrigatório e fretes. O do link vence um ?template_id= na URL, e a sessão aberta pelo link é cobrada por ele — o checkout recusa outro template no pagamento. |
domainId | string | Não | Em que domínio a accessFullUrl é montada (veja abaixo) |
integrationId | string | Não | A integração (app_...) a que uma venda por este link pertence (veja abaixo) |
metadata | object | Não | Metadados livres |
domainId — o domínio do link
domainId escolhe o host da accessFullUrl. Os valores aceitos são os de
GET /v1/domains/listall:
- um domínio próprio seu, desde que pronto — verificado com TLS ativo (
activeessl), comcheckoutnopurposee sem vínculo vivo de área de membros; dmn_shared— o domínio compartilhado da plataforma (pay.selectwin.io), disponível para toda empresa. É a única forma de colocar um link no host da plataforma quando você já tem domínio próprio pronto.
Omitido, o comportamento é o de sempre: o seu domínio de checkout pronto mais antigo, e na falta dele o
pay.selectwin.io.
Um domainId que não resolva (de outra empresa, não verificado, sem checkout no purpose, ou de área de
membros) devolve 422 checkoutDomainIdIsInvalid e o link não é criado. Não existe fallback silencioso
aqui de propósito: um link montado em host de outra empresa abre 404 para o comprador, porque o checkout
resolve o lojista pelo host e recusa quando host e link discordam do dono.
A resposta devolve em domainId o domínio em que o link está — dmn_shared para os que vivem no host da
plataforma, inclusive os criados antes deste campo existir.
integrationId — a que integração a venda pertence
integrationId amarra o link a uma das suas integrações (GET /v1/integrations/list-all). Quando um
comprador abre o link, a sessão de checkout nasce carimbada com:
| campo da sessão | valor |
|---|---|
integrationType | o slug do tipo da integração — woocommerce, shopify, … |
integrationId | o app_... da integração |
É assim que um pedido gerado por um link volta a ser atribuído à loja que o criou, sem que a URL do
comprador precise carregar ?integration=. Se a URL trouxer ?integration=, ela vence — o parâmetro é
um override explícito, e como ele nomeia um tipo (não uma linha sua), o integrationId da sessão fica
nulo nesse caso, em vez de atribuir a venda a uma integração que ninguém pediu.
Uma integração deleted ou quarantined não resolve ⇒ 422 checkoutIntegrationIdIsInvalid. Uma
integração apenas desabilitada resolve normalmente: pausar uma integração não pode quebrar a criação de
links.
Resposta 201 Created
{
"id": "link_01hqzvabc",
"name": "Black Friday PIX",
"type": "dynamic",
"enabled": true,
"accessId": "k3m9x2qp7ab4",
"signature": "f62a0cb72d7a5d55052c96301013e64627133231f90c4614b10d0f50b9887f8d",
"accessFullUrl": "https://pay.selectwin.io/l/live/k3m9x2qp7ab4",
"sessionId": null,
"editable": false,
"items": [ { "id": "var_01hqzvabc", "quantity": 1 } ],
"discounts": [],
"customInputs": [],
"expiresAt": "2026-12-31T23:59:59.000Z",
"availableAt": null,
"templateId": null,
"integrationId": null,
"domainId": null,
"metadata": {},
"createdAt": "2026-04-12T17:56:33.000Z",
"updatedAt": "2026-04-12T17:56:33.000Z"
}| Campo | Descrição |
|---|---|
id | ID público do link (link_*). |
type | Palavra de tipo ecoada do banco (compatibilidade). |
enabled | Se o link está ativo. |
accessId / signature / accessFullUrl | Identificador de acesso, assinatura HMAC e URL pronta para compartilhar. O accessId é uma chave curta e opaca de 12 caracteres (a-z0-9), única na plataforma, e é o que a accessFullUrl carrega em /l/{environment}/{accessId}. Links criados antes de setembro/2026 têm ids de 32 caracteres e continuam válidos — nada reescreve o accessId, então trate-o sempre como string opaca de tamanho variável, nunca com tamanho fixo. |
sessionId | Sempre null (a vinculação link→sessão é resolvida no fluxo público de abertura). |
templateId | tmpl_* quando há template; senão null. |
integrationId / domainId | Sempre null (binding ainda não exposto). |
Consultar
GET /v1/checkouts/payment-links/{paymentLinkId}
Retorna o objeto completo (mesma forma da criação).
curl -X GET "https://api.selectwin.io/v1/checkouts/payment-links/link_01hqzvabc" \
-H "SelectKey: sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ"Listar
GET /v1/checkouts/payment-links
Lista paginada. Cada item traz o objeto completo do link (mesma forma da consulta individual).
Filtros
| Parâmetro | Tipo | Descrição |
|---|---|---|
limit / offset / sort | — | Paginação (limit default 20, máx. 100; offset default 0). Veja Paginação |
status | enum | enabled ou disabled |
domainId | string | Os links que abrem neste host (dmn_…, ou dmn_shared para o host da plataforma): pelo domainId gravado no link ou, quando o host foi escolhido no automático, pela URL do link |
daterange* | — | Filtros por intervalo de datas (daterange, daterangegt, daterangegte, daterangelt, daterangelte) |
Resposta 200 OK
{
"offset": 0,
"limit": 20,
"total": 3,
"page": { "current": 1, "total": 1, "offset": { "first": 0, "prev": null, "next": null, "last": 0 } },
"data": [
{
"id": "link_01hqzvabc",
"name": "Black Friday PIX",
"type": "dynamic",
"enabled": true,
"accessId": "k3m9x2qp7ab4",
"signature": "f62a0cb72d7a5d55052c96301013e64627133231f90c4614b10d0f50b9887f8d",
"accessFullUrl": "https://pay.selectwin.io/l/live/k3m9x2qp7ab4",
"sessionId": null,
"editable": false,
"items": [ { "id": "var_01hqzvabc", "quantity": 1 } ],
"discounts": [],
"customInputs": [],
"expiresAt": "2026-12-31T23:59:59.000Z",
"availableAt": null,
"templateId": null,
"integrationId": null,
"domainId": null,
"metadata": {},
"createdAt": "2026-04-12T17:56:33.000Z",
"updatedAt": "2026-04-12T17:56:33.000Z"
}
],
"hasMore": false
}Atualizar
PUT /v1/checkouts/payment-links/{paymentLinkId}
Envie apenas os campos a alterar: name, items, discounts, customInputs, expiresAt,
availableAt, editable, templateId, domainId, integrationId, metadata. O corpo é estrito —
campos não reconhecidos são rejeitados com 400. Retorna o objeto completo (200 OK), mesma forma da criação.
curl -X PUT "https://api.selectwin.io/v1/checkouts/payment-links/link_01hqzvabc" \
-H "SelectKey: sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ" \
-H "Content-Type: application/json" \
-d '{ "name": "Campanha atualizada", "expiresAt": "2027-01-31T23:59:59Z" }'Testar em sandbox
POST /v1/checkouts/payment-links/{paymentLinkId}/test
Cria o link de teste de um link de produção, sem trocar de ambiente: a chamada é feita com a chave (ou a
sessão) live, e o link criado é de sandbox. O ambiente fica dentro da URL (…/l/sandbox/…), então o link de
teste nunca abre em produção e não cobra de verdade. Sem corpo; aceita X-Idempotency-Key.
- Os itens são cópias. O catálogo de cada ambiente é separado, então cada variante do link ganha uma cópia no
catálogo de
sandbox, com o mesmo nome, preço, recorrência e imagens. Ometadatada cópia guarda de onde ela veio (selectwinLiveVariantId,selectwinLiveProductId). - Um link de teste por link de produção. Chamar de novo refaz o mesmo link de teste, com a mesma URL, e
atualiza as cópias a partir da produção (o preço novo, por exemplo). O
metadatado link de teste guarda o link de produção (selectwinLiveLinkId). A primeira chamada responde201; as seguintes,200. - Abre na hora. O link de teste não herda
availableAtnemexpiresAt, para dar para testar antes de divulgar. - O que não vai junto vem em
warnings. O link de teste abre no checkout padrão dosandbox(o checkout próprio do link é de produção) e não é de nenhuma integração. Item desativado na produção fica de fora, e a cópia dele é desativada. Cupom sem cupom de mesmo código nosandboxnão dá desconto no teste. - Um teste por vez, por conta. Enquanto um link de teste da sua conta está sendo preparado, outra chamada a
/test(de qualquer link) responde409 checkoutPaymentLinkTestBusyna hora, sem gravar nada. Espere alguns segundos e chame de novo com outraX-Idempotency-Key(a chave da tentativa recusada continua devolvendo o 409). - Até 100 itens. O teste copia no máximo 100 itens, o mesmo limite do link. Um link antigo com mais itens que isso
responde
422 checkoutPaymentLinkTestTooManyItems.
curl -X POST "https://api.selectwin.io/v1/checkouts/payment-links/link_01hqzvabc/test" \
-H "SelectKey: sk_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ" \
-H "X-Idempotency-Key: 4f1c2a9e-teste-link"{
"resource": "checkout-paymentLinkTest",
"liveLinkId": "link_01hqzvabc",
"created": true,
"link": {
"id": "link_01hqzvtst",
"name": "Campanha de lançamento",
"accessFullUrl": "https://pay.selectwin.io/l/sandbox/k3v9q2m7x1ab",
"items": [{ "id": "var_01hqzvcpy", "quantity": 1 }],
"...": "o mesmo objeto da criação"
},
"items": [
{ "liveVariantId": "var_01hqzvabc", "variantId": "var_01hqzvcpy", "productId": "prd_01hqzvcpy", "quantity": 1, "copiedNow": true }
],
"warnings": [
{ "code": "couponsNotInSandbox", "values": ["LANCAMENTO10"] },
{ "code": "templateNotCarried" }
]
}warnings[].code | Significado |
|---|---|
variantsNotOnSale | Variantes de produção desativadas, ou de produto desativado, ficaram fora do teste (values: os ids de produção) |
couponsNotInSandbox | Estes códigos não existem no sandbox, e o teste abre sem o desconto deles (values: os códigos) |
templateNotCarried | O link tem checkout próprio, que é de produção. O teste abre no checkout padrão do sandbox |
integrationNotCarried | O link é de uma integração, e a venda de teste não é atribuída a ela |
Excluir
DELETE /v1/checkouts/payment-links/{paymentLinkId}
{ "id": "link_01hqzvabc", "resource": "checkout-paymentLink", "deleted": true }Erros
error.code | HTTP | Quando |
|---|---|---|
invalidParameters | 400 | Validação de campos (veja error.params) |
checkoutPaymentLinkNotFound | 404 | Link não encontrado |
variantIdIsInvalid | 422 | Algum items[].id referencia uma variante inexistente, desativada ou de outro ambiente (um link live não aceita variante de sandbox) |
checkoutTemplateIdIsInvalid | 422 | templateId não existe |
checkoutDomainIdIsInvalid | 422 | domainId não é um domínio que esta empresa pode usar no checkout |
checkoutIntegrationIdIsInvalid | 422 | integrationId não é uma integração desta empresa (ou está deleted/quarantined) |
checkoutPaymentLinkTestFromSandbox | 409 | /test chamado com chave ou sessão de sandbox. Lá, todo link já é de teste |
checkoutPaymentLinkTestNothingToSell | 422 | /test: nenhum item do link está à venda na produção |
checkoutPaymentLinkTestTooManyItems | 422 | /test: o link tem mais de 100 itens (error.params[0].items diz quantos) |
checkoutPaymentLinkTestBusy | 409 | /test: outro link de teste da conta está sendo preparado agora. Nada foi gravado: tente de novo em instantes, com outra X-Idempotency-Key |
checkoutPaymentLinkCreateFailed | 500 | Falha ao criar o link |
Catálogo geral: Códigos de Erro.
Atualizado em 21 de outubro de 2026