Catálogo de Códigos de Erro
Este catálogo lista os valores de error.code que a API pode retornar, agrupados por status HTTP e
por recurso. Para a estrutura do objeto de erro (envelope), veja Tratamento de Erros.
Status HTTP
A API usa códigos de status HTTP padrão. Cada error.code tem sempre o mesmo statusCode e a mesma
category:
category | Status | Significado |
|---|---|---|
validation | 400 | Requisição malformada ou parâmetro inválido (veja error.params) |
authentication | 401 | Credencial (SelectKey / login) ausente, inválida ou revogada |
payment | 402 | Pagamento recusado pelo emissor |
authorization | 403 | Autenticado, mas sem permissão / conta não ativa |
client | 404 | Recurso não encontrado |
client | 409 | Conflito (estado incompatível, duplicidade, idempotência) |
client | 413 | Corpo da requisição grande demais |
validation | 422 | Entidade não processável (regra de negócio) |
rate_limit | 429 | Limite de requisições excedido (veja API Limits) |
server | 500 | Erro interno — tente novamente; se persistir, contate o suporte |
server | 503 | Indisponibilidade temporária de um serviço — repita com backoff |
Códigos comuns (cross-cutting)
Estes códigos vêm do kernel e podem aparecer em qualquer rota (recurso server, exceto onde indicado):
error.code | HTTP | Quando ocorre |
|---|---|---|
invalidParameters | 400 | Falha de validação de contrato (veja error.params para os campos) — inclusive metadata acima do limite (50 chaves, chave ≤ 40 caracteres, valor ≤ 500, objeto ≤ 8 KiB; veja Metadata) |
unauthorized | 401 | SelectKey/token ausente, inválido ou revogado |
actingAccountInvalid | 401 | X-Selectwin-Account com uma credencial que não é chave de API, com uma conta que não é sub-conta da sua plataforma, ou com a sua plataforma fora de active (Marketplace) |
forbidden | 403 | Autenticado, mas sem permissão para a operação |
payloadTooLarge | 413 | Corpo da requisição excede o limite (envie arquivos via /v1/assets) |
tooManyRequests | 429 | Rate limit atingido (veja API Limits) |
idempotencyInProgress | 409 | Já há uma requisição em andamento com esta X-Idempotency-Key |
idempotencyOutcomeUnknown | 409 | A primeira requisição com esta chave não terminou de responder (há mais de 10 min) — pode ter executado; confira e repita com uma chave nova |
idempotencyMismatch | 409 | Esta X-Idempotency-Key já foi usada com um payload diferente |
accountLevelReadOnlyInSandbox | 409 | Recurso authentication. Escrita num recurso de conta (apps/integrações, pixels, área de membros, marketplace, gate do Repart, encerramento) com credencial sandbox (sk_test_… ou painel em Sandbox). Esses recursos têm uma cópia só, a de produção — leia à vontade, altere em live. Cada operação afetada vem marcada com x-account-level na OpenAPI |
serverError | 500 | Erro interno inesperado |
Erros de validação de campos trazem detalhes por campo em error.params:
{
"error": {
"status": "Bad Request",
"statusCode": 400,
"category": "validation",
"code": "invalidParameters",
"message": "Validation errors occurred.",
"resource": "server",
"params": [{ "amount": "amount must be a positive integer" }]
}
}Por recurso
Transactions
error.code | HTTP | Mensagem |
|---|---|---|
transactionNotFound | 404 | Transaction not found |
customerNotFound | 404 | The customer for this transaction was not found |
cardNotFound | 404 | The card for this transaction was not found |
addressNotFound | 404 | The billing address was not found |
recipientNotFound | 404 | A split recipient was not found |
disputeNotFound | 404 | No dispute was found for this transaction |
cardCustomerMismatch | 422 | The card does not belong to the customer |
transactionNotRefundable | 422 | This transaction cannot be refunded in its current status |
refundAmountInvalid | 422 | Refund amount inválido (≤ 0 ou acima do total já cobrado) |
refundInProgress | 409 | A refund for this transaction is already in progress |
refundInsufficientBalance | 422 | The available balance does not cover this refund — the funds for this sale were already paid out |
refundSplitRecipientInsufficientBalance | 422 | A split recipient of this sale does not have the available balance this refund draws from their released share |
transactionNotCapturable | 422 | This transaction is not awaiting capture |
captureAmountInvalid | 422 | Capture amount inválido (≤ 0 ou acima do autorizado) |
transactionNotInDispute | 422 | Defense evidence só pode ser enviada com a transação em disputa |
discountExceedsAmount | 422 | O desconto deixa a cobrança abaixo do mínimo |
splitsExceedAmount | 422 | A soma dos splits excede o valor cobrado |
splitsInvalid | 422 | Um split resolve para valor inválido (zero ou negativo) |
installmentsExceedMax | 422 | Parcelas acima do máximo oferecido no momento |
onBehalfOfInvalid | 422 | onBehalfOf deve referenciar uma sub-conta sua (marketplace habilitado) |
sellerRatesMissing | 422 | Conta sem taxa configurada — não pode transacionar |
chargeCompanyNotActive | 422 | Conta não está active — cobranças indisponíveis (numa cobrança onBehalfOf, avalia a SUB-conta) |
Erros de processamento do pagamento (recurso payments):
error.code | HTTP | Mensagem |
|---|---|---|
paymentDeclined | 402 | The payment was declined by the issuer |
transactionNotFound | 404 | Transaction not found at the provider |
providerUnavailable | 500 | The payment provider is temporarily unavailable |
Marketplace
Sub-contas de uma plataforma (/v1/marketplace/* — guia). Recurso de conta: toda escrita com chave de sandbox responde 409 accountLevelReadOnlyInSandbox.
error.code | HTTP | Mensagem |
|---|---|---|
marketplaceNotEnabled | 403 | A função de marketplace não está habilitada para esta conta |
marketplaceNotApproved | 403 | A função está habilitada, mas aguarda a aprovação de compliance antes de criar sub-contas |
marketplaceNested | 422 | Uma sub-conta não pode ser plataforma nem criar sub-contas |
subAccountLimitReached | 422 | A conta atingiu o limite de sub-contas — fale com o seu gerente de conta |
marketplaceUserRequired | 422 | A conta da plataforma não tem um titular registrado para receber a sub-conta — fale com o suporte |
subAccountNotFound | 404 | Sub-conta não encontrada (ou não pertence à sua plataforma) |
subAccountAlreadyActive | 422 | A sub-conta já está ativa — o link de credenciamento só vale para contas em cadastro |
planNotFound | 404 | Plano de taxas não encontrado (ou não pertence à sua plataforma) |
planFeeTypeMismatch | 422 | Um meio cobrado numa forma (percentual/fixo) diferente da sua própria taxa naquele meio (params: [{ method, field }]) |
platformRatesMissing | 422 | A sua conta ainda não tem taxa configurada, então o plano não pode ser validado |
planReleaseBelowPlatform | 422 | Um prazo de liberação do plano é menor que o prazo em que a plataforma recebe aquele meio (params traz o mínimo por campo) |
planInUse | 409 | O plano está atribuído a sub-contas e não pode ser excluído (params[0].subAccounts) |
subAccountNameLocked | 422 | O nome só muda antes de o cadastro ser enviado — depois ele é parte do registro em análise |
subAccountNotSuspendable | 422 | Só uma sub-conta active pode ser suspensa |
subAccountNotReinstatable | 422 | A sub-conta não foi suspensa pela sua plataforma (ou não está disabled) — só a Selectwin reabilita; fale com o suporte |
subAccountStatusConflict | 409 | O status da sub-conta mudou enquanto a requisição rodava — consulte e repita |
closureRequestNotFound | 404 | A sub-conta não tem pedido de encerramento (consulta ou desistência) — recurso company |
closureRequestNotCancelable | 409 | O encerramento já começou a ser executado e não pode mais ser desfeito — recurso company |
kycLinkInvalid | 404 | O link de credenciamento é inválido, venceu, foi revogado — ou a sub-conta já está ativa |
kycUploadLimitReached | 429 | Uploads demais pelo link de credenciamento na última hora (params[0].limit) |
A plataforma agindo como a sub-conta (X-Selectwin-Account, guia) — recurso authentication:
error.code | HTTP | Mensagem |
|---|---|---|
actingAccountInvalid | 401 | O cabeçalho veio com uma credencial que não é chave de API, com uma conta que não é sub-conta da sua plataforma, ou a sua plataforma não está ativa |
Subscriptions
/v1/subscriptions é Selectwin-strict: a precificação vem das variantes recorrentes; não há campo amount nem preço manual.
error.code | HTTP | Mensagem |
|---|---|---|
subscriptionNotFound | 404 | Subscription not found |
customerNotFound | 404 | The customer for this subscription was not found |
cardNotFound | 404 | The card for this subscription was not found |
variantNotFound | 404 | One or more product variants were not found |
cycleNotFound | 404 | The billing cycle was not found for this subscription |
itemNotFound | 404 | The line item was not found for this subscription |
splitNotFound | 404 | The split was not found for this subscription |
splitRecipientNotFound | 404 | The split recipient company was not found |
meteredItemNotFound | 404 | Metered subscription item not found |
thresholdNotFound | 404 | Billing threshold not found |
cardCustomerMismatch | 422 | The card does not belong to the customer |
variantNotRecurring | 422 | A variant is not priced for recurring billing |
subscriptionStartDateInPast | 422 | billing.startDate cannot be in the past (São Paulo calendar day) |
subscriptionAlreadyCanceled | 422 | This subscription is already canceled |
subscriptionNotModifiable | 422 | A canceled subscription cannot be modified |
subscriptionNotPausable | 422 | This subscription cannot be paused in its current status |
subscriptionNotResumable | 422 | Only a paused subscription can be resumed |
noScheduledCycle | 422 | There is no scheduled cycle to renew for this subscription |
subscriptionRequiresItem | 422 | A subscription must keep at least one line item |
itemCurrencyMismatch | 422 | The item currency must match the subscription currency |
duplicateSplitRecipient | 422 | A split already exists for this recipient |
splitValueInvalid | 422 | A percentage split value must be between 0 and 100 |
usageOnNonMeteredItem | 422 | Usage can only be reported on metered items |
usageActionUnsupported | 422 | Usage action not supported (only 'increment') |
thresholdMisconfigured | 422 | Billing threshold misconfigured |
thresholdAlreadyExists | 409 | A billing threshold already exists for this item |
onBehalfOfInvalid | 422 | onBehalfOf deve referenciar uma sub-conta sua (marketplace habilitado) |
fraudBlocked (recurso antifraud) | 403 | A criação foi recusada pelo antifraude (bloqueio ou pedido de revisão manual — a assinatura não espera revisão) |
Customers
error.code | HTTP | Mensagem |
|---|---|---|
customerNotFound | 404 | Customer not found |
invalidCustomerId | 404 | The provided customer id is invalid |
customerEmailTaken | 409 | A customer with this email already exists |
customerDocumentTaken | 409 | A customer with this document already exists |
customerHasActiveSubscription | 409 | Cliente com assinatura ativa não pode ser excluído (cancele a assinatura antes) |
Cards
error.code | HTTP | Mensagem |
|---|---|---|
cardIdNotFound | 404 | Card ID not found |
cardInUseBySubscription | 422 | Uma assinatura de cartão viva deste cliente cobra este cartão no próximo ciclo; aponte a assinatura para outro antes de apagar. Assinaturas de pix/boleto não contam (geram QR/boleto novo a cada ciclo) |
cardIdIsInvalid | 400 | Card ID is invalid |
cardExpired | 400 | Card expired |
invalidCardData | 422 | Invalid card data |
cardBrandNotSupported | 422 | Card brand not supported |
cardAssociationRateLimited | 429 | Muitas associações de cartão (ou recusas) em pouco tempo nesta conta. Aguarde e tente de novo; se não foi você, fale com o suporte |
Addresses
error.code | HTTP | Mensagem |
|---|---|---|
addressIdNotFound | 404 | Address not found |
Wallets (contas bancárias)
error.code | HTTP | Mensagem |
|---|---|---|
walletNotFound | 404 | Wallet not found |
walletAlreadyExists | 409 | A wallet with these account details already exists |
walletHasPendingWithdrawal | 409 | Wallet com saque em andamento não pode ser excluída |
bankCodeNotSupported | 400 | This bank code is not supported |
Withdrawals (saques)
error.code | HTTP | Mensagem |
|---|---|---|
withdrawalNotFound | 404 | Withdrawal not found |
withdrawalCreateNotEnabled | 400 | Withdrawals are not enabled for this company |
withdrawalAmountLessThanMinimum | 400 | O valor do saque está abaixo do mínimo — error.params[0].minAmount traz o mínimo em centavos (o mesmo de GET /v1/companies/fees → withdrawal.minAmount) |
Auto-cashout (saque automático)
error.code | HTTP | Mensagem |
|---|---|---|
autoCashoutNotFound | 404 | Auto-cashout config not found |
duplicateAutoCashoutForWallet | 400 | An auto-cashout config already exists for this wallet |
percentageOverlapDetected | 400 | A soma das porcentagens habilitadas não pode exceder 100% (regras de conta removida não contam) |
autoCashoutWalletArchived | 422 | A conta de destino da regra foi removida — envie o PUT com outro walletId antes de ligá-la |
Finance (Balance / Receivables)
error.code | HTTP | Mensagem |
|---|---|---|
balanceNotFound | 404 | No balance found for this company yet |
balanceIsInsufficient | 422 | Insufficient available balance for this withdrawal |
balanceHasNoDebt | 422 | Pedido de Pix de quitação (POST /v1/balance/debt-settlements) numa conta sem saldo negativo — não há dívida para quitar |
debtSettlementInProgress | 409 | Outro pedido de quitação da mesma conta está emitindo o Pix neste instante. Aguarde alguns segundos e repita: o Pix em aberto será devolvido |
withdrawalBlockedByDebt | 422 | A conta tem saldo negativo (dívida com a plataforma — em geral estorno ou chargeback depois de um saque). O saque fica bloqueado até a dívida ser quitada, e ela é abatida automaticamente pelos próximos recebíveis liberados. O valor em aberto vem em params[0].owedAmount (centavos) |
withdrawalDuplicateSuspected | 409 | Um segundo POST /v1/withdrawals idêntico (mesma carteira, mesmo valor) chegou em menos de 10 segundos sem X-Idempotency-Key. Nada foi debitado; params[0].withdrawalId é o saque que já existe. Mande sempre a chave de idempotência para reenviar com segurança |
receivableNotFound | 404 | Receivable not found |
Products & Variants
error.code | HTTP | Mensagem |
|---|---|---|
productNotFound | 404 | Product not found |
variantNotFound | 404 | Variant not found |
invalidPricing | 422 | Invalid advanced pricing configuration |
pricingTypeImmutable | 422 | pricing.type is immutable |
pricingSchemaImmutable | 422 | pricing.schema is immutable |
variantRenewalRulesUnavailable | 503 | The renewal rules cannot be saved yet |
Coupons
error.code | HTTP | Mensagem |
|---|---|---|
couponNotFound | 404 | The coupon code was not found |
couponCodeConflict | 409 | A coupon with this code already exists |
couponDisabled | 422 | This coupon is no longer active |
couponNotYetActive | 422 | This coupon is not active yet |
couponExpired | 422 | This coupon has expired |
couponMinCartAmount | 422 | Cart total abaixo do mínimo do cupom |
couponMaxCartAmount | 422 | Cart total acima do máximo do cupom |
couponMinCartItems | 422 | Menos itens do que o cupom exige |
couponMaxCartItems | 422 | Mais itens do que o cupom permite |
couponNotApplicable | 422 | This coupon does not apply to this cart |
couponUsageLimitReached | 422 | This coupon has reached its usage limit |
couponCustomerLimitReached | 422 | This coupon has already been used by this customer |
couponExceedsTotal | 422 | The coupon discount exceeds the chargeable total |
couponAlreadyApplied | 422 | O mesmo cupom foi aplicado mais de uma vez na mesma cobrança |
couponNotCumulative | 422 | Cupom isCumulative:false enviado junto de outro cupom |
Checkout
error.code | HTTP | Mensagem |
|---|---|---|
checkoutSessionNotFound | 404 | Checkout session not found |
sessionHasActivePayment | 409 | Já há um pagamento em voo: 2º submit, ou patch nos campos que a cobrança usa (items, coupons, customer, address, shippingOptionId) (params[0].jobId) |
sessionAlreadyPaid | 409 | A compra desta sessão já está paga, ou aguardando o comprador, por OUTRO pagamento dela — nunca um 2º pagamento da mesma compra (params[0].transactionId, só no submit do lojista) |
checkoutCartChangedDuringPayment | 409 | items/coupons mudaram entre o cálculo do total e o claim do /pay; refaça /totals e /pay com o carrinho atual |
checkoutTemplateMismatch | 409 | O templateId do corpo não é o template com que a sessão nasceu; omita-o ou mande o da sessão |
checkoutCartNotEditable | 422 | O link (editable:false) ou o template trava essa mudança do carrinho (params[0].rule: quantity, removal ou addition) |
exitCouponNotOffered | 404 | Não há cupom de saída para esta sessão (popup desligado, sem código, ou código que não vale agora) |
invalidOrderbump | 400 | Linha de order bump com quantidade que o lojista não ofereceu, ou a mesma variante marcada como bump duas vezes |
upsellPriceChanged | 409 | O expectedAmount/expectedPricingType do aceite não bate com a oferta viva; nada foi cobrado. A oferta atual vem em params[0] ({upsellId, amount, pricingType, currency}) — releia GET /checkout/v1/upsells e mostre o preço que está de fato à venda, nunca reenvie às cegas |
checkoutSessionNotUpdatable | 409 | A completed checkout session can no longer be updated |
checkoutSessionNotPayable | 409 | This checkout session is not in a payable state |
variantIdIsInvalid | 422 | Um item referencia uma variante que não existe, está desligada, pertence a um produto desligado ou ao outro ambiente — error.params[0].items diz qual |
onBehalfOfInvalid | 422 | onBehalfOf deve referenciar uma sub-conta sua (marketplace habilitado) |
checkoutPaymentLinkNotFound | 404 | Payment link not found |
checkoutPaymentLinkCreateFailed | 500 | The payment link could not be created |
checkoutTemplateNotFound | 404 | Checkout template not found |
checkoutTemplateIdIsInvalid | 422 | The checkout template does not exist |
orderbumpNotFound | 404 | Order bump not found |
reviewNotFound | 404 | Checkout review not found |
shippingOptionNotFound | 404 | Shipping option not found |
shippingOptionRequiresTemplateOrGlobal | 422 | A shipping option must be global or bound to a checkout template |
checkoutPixelNotFound | 404 | Checkout tracking pixel not found |
upsellNotFound / upsellOfferNotFound | 404 | Upsell offer not found |
upsellParentNotFound | 404 | Parent transaction not found |
upsellParentNotApproved | 422 | A transação pai precisa estar aprovada para cobrar um upsell |
upsellOfferExpired | 422 | This upsell offer has expired |
upsellOfferNotEligible | 422 | This upsell offer is not eligible for the parent purchase |
upsellAmountTooLow | 422 | The upsell amount is below the minimum chargeable value |
Webhooks
error.code | HTTP | Mensagem |
|---|---|---|
webhookEndpointNotFound | 404 | Webhook endpoint not found |
webhookEventNotFound | 404 | Webhook event not found |
webhookDispatchNotFound | 404 | Webhook dispatch not found |
webhookUnknownResource | 422 | Unknown event resource — cannot build payload |
webhookSigningDisabled | 422 | This endpoint has signing disabled (no secret) |
Domains
error.code | HTTP | Mensagem |
|---|---|---|
domainIdIsInvalid | 404 | Domain ID is invalid (not found for this company) |
domainAlreadyExists | 409 | Domain already exists |
domainLimitExceeded | 409 | Domain limit exceeded |
domainUpdateFailed | 400 | Domain update failed |
domainEdgeProvisionFailed | 422 | Domain edge provisioning failed |
Permissões da conta
Quando a conta tem uma lista de permissões (recursos e operações liberados), uma chave de API que tenta sair dela recebe:
error.code | HTTP | Mensagem |
|---|---|---|
resourceNotAllowed | 403 | This resource is not allowed for this client |
operationMethodNotAllowed | 403 | This operation is not allowed for this client |
Exports
error.code | HTTP | Mensagem |
|---|---|---|
exportNotFound | 404 | The export was not found |
exportNotCancelable | 422 | This export can no longer be canceled |
exportTooLarge | 422 | The export exceeds the maximum allowed row count |
exportTooManyOpen | 429 | Too many exports are still open for this account — at most 3 can be pending or processing at once; wait for one to finish or cancel one |
Assets (upload)
error.code | HTTP | Mensagem |
|---|---|---|
assetNotFound | 404 | The asset was not found |
assetUploadIncomplete | 422 | No uploaded object was found for this asset yet |
assetContentTypeMismatch | 422 | The uploaded file is not of the declared contentType; it was discarded (suba de novo com o Content-Type de upload.headers) |
assetContentTypeUnverified | 503 | The storage could not report the uploaded file type yet; nothing was discarded (chame o confirm de novo — não precisa subir o arquivo outra vez) |
assetCompanyUnresolved | 422 | Could not resolve the company for this upload |
storageNotConfigured | 503 | Object storage is not configured (indisponibilidade temporária) |
Como tratar erros (recomendado)
const res = await fetch(url, { headers: { SelectKey: process.env.SELECTWIN_API_KEY } });
if (!res.ok) {
const { error } = await res.json();
switch (error.code) { // ← key no code, nunca na message
case 'customerNotFound':
return handleMissingCustomer();
case 'balanceIsInsufficient':
return promptTopUp();
case 'paymentDeclined':
return promptAnotherCard();
default:
if (error.statusCode === 429) return retryWithBackoff(); // rate limit
if (error.statusCode >= 500) return retryWithBackoff(); // transitório
throw new Error(`${error.code}: ${error.message}`);
}
}Atualizado em 21 de outubro de 2026