Cria links de checkout, acompanha os pagamentos, recebe avisos e reembolsa — tudo a partir do teu sistema, do teu CRM ou de uma automação. É a mesma máquina que serve o painel da komm, exposta por HTTP.
Todos os endpoints vivem sob um único URL base. A versão faz parte do caminho: dentro da v1 só acrescentamos coisas, nunca quebramos o que já existe.
URL base
https://komm.pt/api/v1
Começar
Autenticação
Cada pedido leva uma chave de API no cabeçalho Authorization. Geras as tuas chaves no painel, em Conta → API, escolhendo o que cada uma pode fazer.
Cabeçalho
Authorization: Bearer kk_a_tua_chave_aqui
A chave aparece por inteiro uma única vez, no momento em que a crias — guardamos apenas uma impressão digital dela, por isso não conseguimos mostrá-la outra vez. Se a perderes, revoga e cria outra. Uma chave pertence sempre a uma loja e nunca vê dados de outra.
checkout:read
Ler checkouts e pedidos associados
checkout:write
Criar e gerir links de checkout
checkout:refund
Reembolsar pedidos
catalog:read
Ler catálogos, produtos e modelos
webhooks:read
Ler subscrições de webhook
webhooks:write
Gerir subscrições de webhook
Dá a cada chave só o que ela precisa. Se um pedido exigir um âmbito que a chave não tem, recebes 403 forbidden_scope com o âmbito que falta. Repara que checkout:refund é separado de checkout:write de propósito: devolver dinheiro merece um portão a mais.
Começar
Convenções
Quatro regras que valem para toda a API.
Dinheiro em cêntimos
Sempre números inteiros, nunca decimais: 1499 são 14,99 €. Vale para preços, totais e comissões. A moeda é o euro.
Datas em ISO 8601, UTC
2026-07-28T14:37:23.148Z. Também é este o formato do parâmetro cursor nas listagens.
Paginação por cursor
As listagens devolvem data e nextCursor. Para a página seguinte, reenvia o mesmo pedido com cursor igual a esse valor. Quando nextCursor vem null, chegaste ao fim.
Erros com um código estável
Programa contra o code, não contra a mensagem. O código nunca muda dentro da v1; a mensagem pode ser reescrita para ficar mais clara.
Começar
Idempotência
Os pedidos que criam um link ou movimentam dinheiro exigem o cabeçalho Idempotency-Key. É o que garante que uma rede instável não te deixa com dois links ou dois reembolsos.
Usa um valor único por operação — um UUID, ou o identificador da venda no teu sistema. Se repetires a chamada com a mesma chave e o mesmo corpo, devolvemos a resposta original sem executar nada de novo. Se usares a mesma chave com um corpo diferente, recebes 409 idempotency_conflict — é um sinal de que há um erro na tua lógica de repetição, não um pedido a rejeitar às cegas.
Começar
Como o modelo de checkout é escolhido
Cada link usa um modelo — a página que o cliente vê e os campos que lhe são pedidos. Não precisas de escolher: se não enviares modelId, a komm deriva o modo a partir dos produtos e usa o modelo adequado.
physical
Todos os itens são produtos físicos ou kits.
digital
Todos os itens são produtos digitais ou serviços.
hybrid
A venda mistura produtos físicos e digitais.
scheduling
Há um produto de agenda. Nunca se mistura com outros, porque só o modelo de agenda sabe pedir o horário.
Se enviares um modelId que não sirva para os produtos, não te deixamos adivinhar: o erro diz o modo que os teus itens produziram e lista os modelos que aceitamos.
422 model_incompatible
{
"error": {
"code": "model_incompatible",
"message": "Model 'digital-v1' does not fit these products; your items resolve to mode 'physical'. Compatible models: mvp-1, impulso-fisico-v1.",
"details": {
"requestedModelId": "digital-v1",
"resolvedMode": "physical",
"compatibleModelIds": ["mvp-1", "impulso-fisico-v1"]
}
}
}
Endpoints
Catálogo
Leitura dos teus catálogos, produtos e modelos disponíveis. É por aqui que começas: precisas de um productId para criar um checkout.
Listar catálogos
GET/catalogs
âmbito catalog:read
Catálogos da tua loja, cada um com os produtos e o preço já resolvido. O preço de catálogo tem prioridade sobre o preço base do produto — é este valor que um checkout congela quando não envias um preço explícito.
curl -X GET 'https://komm.pt/api/v1/products' \
-H 'Authorization: Bearer A_TUA_CHAVE'
Listar modelos de checkout
GET/checkout-models
âmbito catalog:read
Modelos de checkout compatíveis com um modo. Raramente precisas deste endpoint: se não enviares modelId ao criar uma sessão, a komm escolhe o modelo adequado aos produtos.
Parâmetros de query
mode
physical | digital | hybrid | scheduling
O modo do checkout. Por omissão hybrid. Ver "Como o modelo é escolhido".
hasCustomer
true | false
Inclui os modelos que exigem um cliente associado. Por omissão false.
Resposta
{
"data": [
{
"id": "digital-v1",
"name": "Entrega Digital",
"description": "\"Para onde envio o teu acesso?\" — ultra-minimalista, só pede email.",
"type": "digital",
"requiresCustomer": false
}
]
}
curl
curl -X GET 'https://komm.pt/api/v1/checkout-models' \
-H 'Authorization: Bearer A_TUA_CHAVE'
Endpoints
Links de checkout
O coração da API. Criar o link que envias ao cliente, acompanhar o pagamento e reembolsar quando for preciso.
Criar link de checkout
POST/checkout-sessions
âmbito checkout:writeexige Idempotency-Key
Cria e publica um link de checkout. A resposta traz o url para enviares ao cliente e o id para consultares o estado depois.
Corpo do pedido
nameobrigatório
string
Nome interno, para te orientares no painel. O cliente não o vê.
itemsobrigatório
array (1–20)
Os produtos a vender. Campos de cada item abaixo.
items[].productIdobrigatório
uuid
Produto ativo da tua loja.
items[].quantity
number (1–99)
Quantidade. Por omissão 1.
items[].priceCurrent
number (cêntimos)
O que o cliente paga. Omitido, usa o preço do catálogo ou o preço base do produto.
items[].priceFrom
number (cêntimos)
O preço riscado ("antes"). Tem de ser maior ou igual a priceCurrent.
items[].catalogId
uuid
Catálogo de origem da venda. Determina as comissões de parceiros e afiliados.
customerId
uuid
Associa um cliente existente. Permite os modelos "com cliente", que dispensam pedir nome e email no checkout.
modelId
string
Força um modelo de checkout. Omitido, a komm escolhe o adequado aos produtos.
redirectUrl
url
Para onde o cliente segue depois de pagar, através de um botão "Continuar".
Em vez de fazer polling, subscreve um webhook: recebes o aviso no momento em que o pedido muda de estado.
order.status percorre pending → paid | failed, e paid → refunded quando reembolsas.
curl
curl -X GET 'https://komm.pt/api/v1/checkout-sessions/{id}' \
-H 'Authorization: Bearer A_TUA_CHAVE'
Listar links
GET/checkout-sessions
âmbito checkout:read
Os teus links de checkout, mais recentes primeiro.
Parâmetros de query
status
draft | published | paused | archived
Filtra pelo estado do link.
customerId
uuid
Só os links associados a este cliente.
limit
number (1–100)
Por omissão 20.
cursor
ISO 8601
Passa o nextCursor da resposta anterior.
curl
curl -X GET 'https://komm.pt/api/v1/checkout-sessions' \
-H 'Authorization: Bearer A_TUA_CHAVE'
Pausar, reativar ou arquivar
POST/checkout-sessions/{id}/pause
âmbito checkout:write
Três endpoints com o mesmo formato, sem corpo: /pause deixa de aceitar compras, /reactivate volta a publicar com o mesmo código curto, /archive encerra o link definitivamente.
status refunded significa resolvido de imediato. status pending_refund aparece em pagamentos por cartão via Stripe: o reembolso conclui-se quando o gateway confirmar, e recebes o evento order.refunded nessa altura.
Se as comissões dos parceiros já tiverem sido transferidas, o reembolso automático é recusado com 409 transfers_already_paid — o dinheiro já saiu para terceiros e a reversão exige tratamento manual.
As comissões ainda não transferidas passam a anuladas, mantendo o histórico.
Cada entrega leva dois cabeçalhos: Komm-Signature e Komm-Timestamp. Calcula um HMAC-SHA256 sobre a string {timestamp}.{corpo} usando o segredo da subscrição, e compara com a assinatura recebida. O timestamp entra no cálculo para que uma entrega capturada não possa ser reenviada mais tarde por terceiros — rejeita pedidos com mais de cinco minutos.
Usa o corpo cru do pedido, exatamente como chegou. Se o teu framework fizer parse do JSON e tu voltares a serializá-lo, a assinatura deixa de bater.
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto'
function verificar(corpoRaw, cabecalhos, segredo) {
const timestamp = Number(cabecalhos['komm-timestamp'])
const recebida = cabecalhos['komm-signature']
// Rejeita entregas antigas (proteção contra reenvio).
if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > 300) return false
const esperada =
'sha256=' +
createHmac('sha256', segredo)
.update(`${timestamp}.${corpoRaw}`)
.digest('hex')
const a = Buffer.from(esperada)
const b = Buffer.from(recebida)
return a.length === b.length && timingSafeEqual(a, b)
}
Responde 2xx assim que receberes; qualquer outro código conta como falha e fica registado. Podes ver o resultado de cada tentativa em /webhook-subscriptions/{id}/deliveries ou no painel, em Conta → API. Para experimentar sem esperar por uma venda, usa o endpoint de ping.
Referência
Erros
Todos os erros têm a mesma forma. O code é um contrato estável; a message explica o que corrigir; details e fieldErrors dão o contexto quando ajuda.
Forma do erro
{
"error": {
"code": "product_not_found",
"message": "productId does not match an active product of your store.",
"details": { "productId": "3f2b1c4d-9a8e-4b7c-8d6f-1e2a3b4c5d6e" }
}
}
HTTP
Código
Quando acontece
401
unauthorized
Chave ausente, malformada, revogada ou expirada.
403
forbidden_scope
A chave é válida mas não tem o âmbito que o endpoint exige. details.requiredScope diz qual falta.
404
not_found
O recurso não existe — ou existe e pertence a outra loja. Devolvemos 404 nos dois casos, de propósito, para não revelar a existência de dados de terceiros.
422
validation_failed
O corpo ou os parâmetros não passam a validação. fieldErrors diz que campo falhou e porquê.
422
product_not_found
O productId não corresponde a um produto ativo da tua loja. Inclui produtos em rascunho ou arquivados.
422
catalog_not_found
O catalogId não é um catálogo da tua loja.
422
customer_not_found
O customerId não é um cliente da tua loja.
422
model_incompatible
O modelId escolhido não serve para os produtos enviados. A resposta diz o modo resolvido e a lista de modelos compatíveis.
422
model_requires_customer
O modelo exige um cliente associado, mas não enviaste customerId.
422
scheduling_single_item
Um checkout de agenda só pode ter um item — só esse modelo sabe pedir o horário.
400
missing_idempotency_key
Falta o header Idempotency-Key num endpoint que cria ou movimenta dinheiro.
409
idempotency_conflict
Reutilizaste um Idempotency-Key com um corpo diferente do original.
409
not_refundable
O pedido não está pago, ou já foi reembolsado. details.orderStatus mostra o estado atual.
409
transfers_already_paid
As comissões já foram transferidas para os parceiros. O reembolso exige revisão manual.
409
invalid_status_transition
A transição de estado não é possível — pausar um link não publicado, por exemplo.
429
rate_limited
Demasiados pedidos num curto intervalo. details.retryAfterSeconds diz quanto esperar.
500
internal_error
Falha do nosso lado. details.requestId identifica a ocorrência — envia-nos esse id.
Pronto para começar?
Cria a tua primeira chave no painel e usa o endpoint de produtos para descobrir o que já tens à venda. Daí a criar um link de checkout é uma chamada.