# Disrupty — API de Sellers > A API de Sellers do Disrupty permite que sellers e facilitadores B2B criem vendas (PIX, cartão, boleto), gerenciem produtos e ofertas, sincronizem catálogo B2B, configurem webhooks e solicitem saques via integração server-to-server. REST + JSON. Dois hosts: sellers usam `https://api-sellers.disruptybr.app`; facilitadores B2B usam `https://api.disruptybr.app`. Documentação navegável: https://docs.disruptybr.app/developers — este arquivo é auto-suficiente e contém os detalhes completos inline. Notas importantes: - Autenticação: API key (dois headers `x-api-public-key` + `x-api-private-key`, ambos juntos — um sem o outro retorna 401) ou `Authorization: Bearer `. Server-side apenas; nunca exponha a chave privada no client. - `amount` = preço do produto puro, SEM a taxa do cliente. A plataforma adiciona automaticamente a taxa (`customerFeeAmount`) ao `totalAmount`. Embutir a taxa no `amount` ou em `items[]` cobra o cliente em DOBRO. - Valores no REQUEST são em REAIS (decimal, ex.: `39.99`); valores no RESPONSE são em CENTAVOS (inteiro, ex.: `3999`). Exceção: `POST /api/public/cashout` responde `amount` em reais. Mandar `amount` em centavos no request NÃO dá erro — cria a venda com valor 100x maior. - `customerFee` enviado no body é aceito mas sempre ignorado — a taxa é derivada server-side pela política fiscal do seller. - Consistência: `amount + discountAmount` deve aproximar `Σ(items[].unitPrice × quantity)` com tolerância de 5 centavos; violação retorna 400. - `forbidNonWhitelisted` está ativo em todos os endpoints: qualquer campo fora do schema declarado retorna 400. - Status de venda nasce `PENDENTE` após o 201; a confirmação é assíncrona. Nunca trate o 201 como pagamento confirmado — use o webhook outbound (`type: TRANSACTION`) ou `GET /api/sales/:id`. - Para PIX, `customer.document` (CPF/CNPJ) é OBRIGATÓRIO na prática — o adquirente exige. Sem ele a venda falha com `400 PAYMENT_FAILED`, mesmo com o resto do payload válido. - `400 PAYMENT_FAILED` = não foi possível gerar a cobrança (NÃO é erro de schema). Causas comuns: (a) faltou `customer.document` (CPF/CNPJ) numa venda PIX; (b) o seller não tem adquirente ativo para o método. - Recursos são ownership-scoped: ID de outro seller retorna 404, indistinguível de "não existe". - `webhookUrl` deve ser HTTPS; URLs HTTP são rejeitadas com 400. - Modo `gateway` (default) vs `processor` via header `X-Disrupty-Mode`: em `gateway` você é dono dos produtos (usar `offerId`/`productId` de outro seller retorna `403 CROSS_TENANT_ATTEMPT_BLOCKED`); em `processor` (facilitador B2B vendendo produto de terceiro) o cross-tenant é permitido, mas `productOwnerExternalId` no body é obrigatório. Conceitos (referência navegável): [Visão geral](https://docs.disruptybr.app/developers/overview) · [Quickstart](https://docs.disruptybr.app/developers/quickstart) · [Autenticação](https://docs.disruptybr.app/developers/authentication) · [Ambientes](https://docs.disruptybr.app/developers/environments) · [Rate limits](https://docs.disruptybr.app/developers/rate-limits) · [Erros](https://docs.disruptybr.app/developers/errors) · [Webhooks](https://docs.disruptybr.app/developers/webhooks-concept) --- ## Autenticação Todo request exige autenticação. Duas opções: API key (recomendado para server-to-server) — os dois headers juntos: ``` x-api-public-key: x-api-private-key: ``` JWT (sessão de usuário): ``` Authorization: Bearer ``` Enviar a chave pública sem a privada (ou vice-versa) resulta em 401. As chaves são emitidas no painel Disrupty, na conta do seller. --- ## Vendas ### POST /api/sales — Criar venda Referência: https://docs.disruptybr.app/developers/sales-create Cria uma venda. Para PIX e boleto, retorna os dados de cobrança (QR code / linha digitável) na resposta. Resposta de sucesso: `201 Created`. Headers: | Header | Obrigatório | Valor | |---|---|---| | `Content-Type` | sim | `application/json` | | `x-api-public-key` + `x-api-private-key` | sim (ou JWT) | suas chaves | | `X-Disrupty-Mode` | não | `gateway` (default) ou `processor` | Campos do body (valores monetários em REAIS): | Campo | Tipo | Obrig. | Descrição | |---|---|---|---| | `amount` | number (reais, >0) | sim | Preço do produto puro, SEM a taxa do cliente | | `paymentMethod` | enum | sim | `PIX`, `CREDIT_CARD`, `DEBIT_CARD`, `BOLETO`, `TRANSFER`, `PAYPAL` | | `customer` | object | sim | `{ name, email }` sempre obrigatórios. `document` (CPF/CNPJ) é OBRIGATÓRIO para PIX (sem ele → `PAYMENT_FAILED`); aliases `cpf`/`cnpj` aceitos. `phone`, `countryCode` opcionais | | `items` | array | sim | `[{ title, unitPrice (reais), quantity }]`; `productId`, `sku`, `tangible` opcionais por item. (Alias legado: `products[]`.) | | `currency` | enum | não | `BRL` (default), `USD` | | `discountAmount` | number (reais) | não | Desconto já aplicado. Muda a consistência para `amount + discountAmount ≈ Σ items`. Comissões/taxas incidem sobre `amount` | | `couponCode` | string | não | Apenas rastreabilidade — não valida o cupom | | `installments` | object | não | `{ number (1-12), type?: MERCHANT|ACQUIRER, value? }` — cartão | | `card` | object | não | Dados/token do cartão: `token`, `paymentToken`, `number`, `holderName`, `expirationMonth`, `expirationYear`, `cvv`. Prefira tokenização | | `boleto` | object | não | `{ dueDate?, instructions? }` | | `shipping` | object | não | Endereço de entrega | | `offerId` | int | não | Vincula oferta cadastrada | | `productId` | int | não | Vincula produto cadastrado | | `postbackUrl` | url | não | Webhook de status desta venda específica | | `orderId` / `externalId` | string | não | Identificador externo para idempotência/rastreio | | `metadata` | object | não | Chaves livres (persistidas na venda) | | `utmSource`, `utmMedium`, `utmCampaign`, `utmContent`, `utmTerm`, `src`, `sck` | string | não | Parâmetros de tracking | | `productOwnerExternalId` | string | condicional | Obrigatório em `processor` mode. Identifica o produtor real | | `testMode` | boolean | não | Sinalização de teste | | `customerFee` | number | — | Aceito mas sempre IGNORADO (derivado server-side) | Exemplo mínimo — PIX: ```json { "amount": 39.99, "paymentMethod": "PIX", "customer": { "name": "João Pedro", "email": "joao@exemplo.com", "document": "12345678909" }, "items": [ { "title": "Kit Básico", "unitPrice": 39.99, "quantity": 1 } ] } ``` Exemplo com desconto (consistência: `amount(80) + discountAmount(20) == Σ items(100)`): ```json { "amount": 80.00, "discountAmount": 20.00, "paymentMethod": "PIX", "customer": { "name": "Maria", "email": "maria@exemplo.com", "document": "12345678909" }, "items": [{ "title": "Curso", "unitPrice": 100.00, "quantity": 1 }] } ``` Exemplo cartão de crédito com parcelamento: ```json { "amount": 199.90, "paymentMethod": "CREDIT_CARD", "customer": { "name": "Ana Lima", "email": "ana@exemplo.com", "document": "98765432100" }, "items": [{ "title": "Produto Premium", "unitPrice": 199.90, "quantity": 1 }], "installments": { "number": 3 }, "card": { "token": "tok_...", "holderName": "ANA LIMA" } } ``` Exemplo processor mode (header `X-Disrupty-Mode: processor`): ```json { "amount": 59.90, "paymentMethod": "PIX", "customer": { "name": "Carlos", "email": "carlos@exemplo.com", "document": "12345678909" }, "items": [{ "title": "Produto de Terceiro", "unitPrice": 59.90, "quantity": 1 }], "productOwnerExternalId": "seller_externo_123", "productId": 4521 } ``` Shape da resposta (201) — valores monetários em CENTAVOS: ```jsonc { "message": "Venda criada com sucesso", "sale": { "id": 1834995, "amount": 3999, // produto puro em centavos "customerFeeAmount": 99, // taxa adicionada pela plataforma "totalAmount": 4098, // o que o cliente paga = amount + customerFeeAmount "status": "PENDENTE", "paymentMethod": "PIX", "items": [ { "id": 1, "title": "Kit Básico", "unitPrice": 3999, "quantity": 1, "tangible": false } ], "customer": { "name": "...", "email": "...", "document": "...", "phone": "..." }, "payment": { "method": "PIX", "installments": null, "pix": { "key": "", "qrCodeBase64": "", "expiresAt": "2026-06-18T18:00:00Z" }, "card": null, "boleto": null } } } ``` Como ler a cobrança na resposta: - PIX: `sale.payment.pix.key` é o copia-e-cola / BR Code (sempre presente). `sale.payment.pix.qrCodeBase64` (imagem PNG) pode NÃO vir, dependendo do adquirente — se ausente, gere o QR a partir do `key`. - Boleto: `sale.payment.boleto.code`. - Cartão: 201 indica autorização; `status` nasce `PENDENTE` até confirmar a captura via webhook. Erros comuns: | HTTP / código | Causa | Correção | |---|---|---| | `400` consistência | `amount (+discount) != Σ items` | Use `amount` = produto puro; não inclua taxa nos `items` | | `400` forbidNonWhitelisted | Campo não suportado no body | Remova chaves fora da tabela de campos | | `400 SALE_VALIDATION` | Campo obrigatório ausente/ inválido | Veja `fieldErrors`/`details` no body | | `400 PAYMENT_FAILED` | Não foi possível gerar a cobrança | Cheque `customer.document` (CPF/CNPJ obrigatório p/ PIX); ou seller sem adquirente ativo. Não é erro de schema | | `403 CROSS_TENANT_ATTEMPT_BLOCKED` | `offerId`/`productId` de outro seller em gateway mode | Use processor mode + `productOwnerExternalId`, ou apenas recursos próprios | | valor 100x | `amount` enviado em centavos | Request é em REAIS (`39.99`, não `3999`) | ### GET /api/sales/:id — Consultar venda Referência: https://docs.disruptybr.app/developers/sales-get Consulta uma venda por ID. Resposta: `200 OK` com o objeto da venda (mesmo shape do campo `sale` do POST). Tenant-scoped: ID de outro seller retorna 404. Campos relevantes no response: | Campo | Tipo | Descrição | |---|---|---| | `id` | int | ID da venda | | `status` | enum | `PENDENTE`, `PAGO`, `CANCELADO`, `REEMBOLSADO`, `CHARGEBACK`, `AGUARDANDO`, `EXPIRADO` | | `amount` | int (centavos) | Valor do produto | | `customerFeeAmount` | int (centavos) | Taxa adicionada ao cliente | | `totalAmount` | int (centavos) | Total cobrado do cliente | | `paymentMethod` | enum | Método de pagamento usado | | `payment` | object | Dados de pagamento (`pix`, `card`, `boleto`) | | `customer` | object | Dados do cliente | | `items` | array | Linhas de produto | | `metadata` | object | Chaves livres enviadas no POST | Gotcha: `status: PAGO` não garante que o crédito foi processado internamente — para processos dependentes de comissão/ledger, use o webhook outbound (`type: TRANSACTION`). --- ## Produtos ### POST /api/products — Criar produto Referência: https://docs.disruptybr.app/developers/products-create — Resposta: `201 Created`. | Campo | Tipo | Obrig. | Descrição | |---|---|---|---| | `name` | string (1-255) | sim | Nome do produto | | `price` | number (reais) | sim | Preço base do produto | | `description` | string (max 5000) | não | Descrição longa | | `image` | string (URL) | não | URL da imagem de capa | | `productType` | enum | não | `DIGITAL`, `PHYSICAL`, `SERVICE`, `EVENT` | | `deliveryType` | enum | não | `DOWNLOAD`, `EMAIL`, `REDIRECT`, `MANUAL` | | `category` | string | não | Categoria do produto | | `sacName` | string | não | Nome do suporte (SAC) | | `sacEmail` | string (email) | não | Email do suporte (SAC) | | `openForAffiliation` | boolean | não | Permite afiliados | | `affiliationApprovalMode` | enum | não | `MANUAL` ou `AUTOMATIC` | ### GET /api/products — Listar produtos Referência: https://docs.disruptybr.app/developers/products-list — Lista paginada dos produtos do seller autenticado. ### GET /api/products/:id — Consultar produto Referência: https://docs.disruptybr.app/developers/products-get-by-id — Produto por ID. Tenant-scoped (404 para ID de outro seller). ### PUT /api/products/:id — Atualizar produto Referência: https://docs.disruptybr.app/developers/products-update — Todos os campos opcionais. Whitelist: `name`, `description`, `image`, `productType`, `deliveryType`, `category`, `sacName`, `sacEmail`, `openForAffiliation`, `affiliationApprovalMode`. Campos NÃO aceitos: `price`, `storeId`, `status` (enviá-los retorna 400). Para alterar o preço, use a oferta vinculada. ### DELETE /api/products/:id — Remover produto Referência: https://docs.disruptybr.app/developers/products-delete — Tenant-scoped. Remover produto com ofertas ativas pode ser rejeitado dependendo do estado das ofertas. --- ## Ofertas Ofertas são configurações de venda de um produto: preço, método de pagamento, URLs de redirect, comissão de afiliado, etc. Um produto pode ter múltiplas ofertas. ### POST /api/offers — Criar oferta Referência: https://docs.disruptybr.app/developers/offers-create — Resposta: `201 Created`. | Campo | Tipo | Obrig. | Descrição | |---|---|---|---| | `productId` | int | sim | ID do produto pai (imutável após criação) | | `price` | number (reais) | sim | Preço desta oferta | | `paymentMethod` | enum | não | Método de pagamento aceito (`PIX`, `CREDIT_CARD`, etc.) | | `name` | string | não | Nome identificador da oferta | | `successUrl` | string (URL) | não | Redirect após pagamento confirmado. `""` é transformado em null | | `failUrl` | string (URL) | não | Redirect após falha. `""` é transformado em null | | `backRedirectUrl` | string (URL) | não | Redirect ao voltar sem concluir | | `commission` | number (0-100) | não | Comissão para afiliados em percentual | | `subscriptionInterval` | enum | não | `MONTHLY`, `BIMONTHLY`, `QUARTERLY`, `SEMIANNUAL`, `YEARLY`, `WEEKLY` | | `trialPeriodDays` | int | não | Dias de trial para assinaturas | Gotcha `successUrl`/`failUrl`: a API transforma `""` (string vazia) em null antes da validação. Para limpar essas URLs, envie `""`. ### GET /api/offers — Listar ofertas Referência: https://docs.disruptybr.app/developers/offers-list — Ofertas do seller autenticado. ### GET /api/offers/:id — Consultar oferta Referência: https://docs.disruptybr.app/developers/offers-get-by-id — Tenant-scoped. ### PUT /api/offers/:id — Atualizar oferta Referência: https://docs.disruptybr.app/developers/offers-update — Todos os campos opcionais. `productId` é imutável. Aceitos: `price`, `paymentMethod`, `name`, `successUrl`, `failUrl`, `backRedirectUrl`, `commission`, `subscriptionInterval`, `trialPeriodDays`. ### DELETE /api/offers/:id — Remover oferta Referência: https://docs.disruptybr.app/developers/offers-delete — Tenant-scoped. --- ## Catálogo Sync (B2B) Endpoints sob `/api/seller/*` para sincronização de catálogo por plataformas facilitadoras que gerenciam produtos e ofertas em nome de sellers (use junto com processor mode quando aplicável). Mesma autenticação (API key ou JWT). - POST `/api/seller/products` — Cria produto via integração B2B. Campos similares a `POST /api/products`. Ref: https://docs.disruptybr.app/developers/seller-sync-create-product - PUT `/api/seller/products/:id` — Atualiza produto via integração B2B. Ref: https://docs.disruptybr.app/developers/seller-sync-update-product - POST `/api/seller/offers` — Cria oferta via integração B2B. Campos similares a `POST /api/offers`. Ref: https://docs.disruptybr.app/developers/seller-sync-create-offer - PUT `/api/seller/offers/:id` — Atualiza oferta via integração B2B. Ref: https://docs.disruptybr.app/developers/seller-sync-update-offer - POST `/api/seller/products/:productId/orderbumps` — Cria order bump no produto (oferta adicional no checkout). Ref: https://docs.disruptybr.app/developers/seller-sync-create-orderbump - PUT `/api/seller/products/:productId/orderbumps/:orderbumpId` — Atualiza order bump (requer ID do produto e do orderbump na URL). Ref: https://docs.disruptybr.app/developers/seller-sync-update-orderbump - POST `/api/seller/products/:productId/upsells` — Cria upsell no produto. Ref: https://docs.disruptybr.app/developers/seller-sync-create-upsell - PUT `/api/seller/products/:productId/upsells/:upsellId` — Atualiza upsell (requer ID do produto e do upsell na URL). Ref: https://docs.disruptybr.app/developers/seller-sync-update-upsell --- ## Webhooks ### POST /api/webhook — Registrar webhook Referência: https://docs.disruptybr.app/developers/webhook-create — Resposta: `201 Created`. | Campo | Tipo | Obrig. | Descrição | |---|---|---|---| | `webhookUrl` | string (HTTPS) | sim | URL que recebe as notificações. DEVE ser HTTPS | | `notifyTransactions` | boolean | não | Notificar eventos de venda (default: true) | | `notifyWithdrawals` | boolean | não | Notificar eventos de saque (default: false) | Gotcha: `webhookUrl` com HTTP é rejeitada com 400. Sem exceções para ambientes de desenvolvimento — use um túnel HTTPS (ngrok, etc.). ### GET /api/webhook — Listar webhooks Referência: https://docs.disruptybr.app/developers/webhook-list — Webhooks configurados para o seller. ### PUT /api/webhook/:id — Atualizar webhook Referência: https://docs.disruptybr.app/developers/webhook-update — Campos: `webhookUrl`, `notifyTransactions`, `notifyWithdrawals` (todos opcionais). ### DELETE /api/webhook/:id — Remover webhook Referência: https://docs.disruptybr.app/developers/webhook-delete — Tenant-scoped. ### Payload outbound Quando um evento ocorre, o Disrupty faz um POST na `webhookUrl` configurada. Headers outbound: ``` User-Agent: Disrupty-Webhook/1.0 Content-Type: application/json ``` Payload de transação (`type: TRANSACTION`) — valores em CENTAVOS: ```json { "type": "TRANSACTION", "id": 1834995, "userId": 123, "amount": 3999, "date": "2026-06-18T14:00:00Z", "status": "PAGO", "paymentMethod": "PIX", "customerDocument": "12345678909", "customerEmail": "joao@exemplo.com", "customerName": "João Pedro", "customerPhone": "11999999999", "pixKey": "joao@exemplo.com", "boletoCode": null, "shipping": null, "fee": 99, "saleItems": [ { "title": "Kit Básico", "unitPrice": 3999, "quantity": 1 } ], "transactionId": "txn_abc123" } ``` Payload de saque (`type: WITHDRAWAL`) — valores em REAIS; status do enum em inglês (`PENDING`, `COMPLETED`, `CANCELLED`, `REJECTED`, `PROCESSING`): ```json { "type": "WITHDRAWAL", "id": 9876, "userId": 123, "amount": 150.00, "pixKey": "cpf_do_seller", "pixKeyType": "CPF", "status": "COMPLETED", "externalId": "ext_xyz", "createdAt": "2026-06-18T10:00:00Z", "updatedAt": "2026-06-18T10:05:00Z", "user": { "id": 123, "name": "Nome do Seller", "email": "seller@exemplo.com" } } ``` Deduplicação: o Disrupty bloqueia reenvio do mesmo evento dentro de 24h, mas apenas se o status não mudou. Se o status mudar (ex.: `PENDENTE -> PAGO`), uma nova notificação é enviada mesmo dentro da janela. Sua URL deve responder 200; em timeout/erro o Disrupty pode reenviar — implemente idempotência pelo campo `id`. Lembre: transação em CENTAVOS, saque em reais. --- ## Parcelamento ### GET /api/installments/rules — Regras de parcelamento Referência: https://docs.disruptybr.app/developers/installments-rules Endpoint público (sem autenticação) com as regras de elegibilidade de parcelamento por moeda e bandeira. Usado pelo checkout para renderizar o dropdown de parcelas. Query params (todos opcionais): `currency` (ex.: `BRL`, `USD`; sem ele retorna todas as moedas), `brand` (ex.: `visa`, `mastercard`, em minúsculas; requer `currency`). Response sem params (todas as moedas): ```json { "rules": { "BRL": { "currency": "BRL", "allowedBrands": ["visa", "mastercard", "elo"], "allowedTypes": ["MERCHANT", "ACQUIRER"], "minCount": 2, "maxCount": 12, "allowedCounts": null } } } ``` Response com `currency` + `brand`: ```json { "eligible": true, "currency": "BRL", "brand": "visa", "allowedBrands": ["visa", "mastercard", "elo"], "allowedTypes": ["MERCHANT", "ACQUIRER"], "minCount": 2, "maxCount": 12, "allowedCounts": null } ``` Campos: `allowedBrands` (bandeiras com parcelamento), `allowedTypes` (`MERCHANT` = seller absorve juros / `ACQUIRER` = cliente absorve), `minCount`, `maxCount`, `allowedCounts` (lista restrita ou null = qualquer valor entre min e max), `eligible` (retornado quando `currency` + `brand` informados). Gotcha: `brand` só filtra se `currency` também for informado. --- ## Saque ### POST /api/public/cashout — Solicitar saque via Pix Referência: https://docs.disruptybr.app/developers — Resposta: `201 Created`. Solicita um saque do saldo disponível do seller para uma chave Pix. Body: ```json { "amount": 500.00, "pixKey": "cpf_ou_email_ou_chave_aleatoria", "pixKeyType": "CPF" } ``` | Campo | Tipo | Obrig. | Descrição | |---|---|---|---| | `amount` | number (reais) | sim | Valor do saque em REAIS. Limites efetivos service-side: mín. 20, máx. 10000 por operação | | `pixKey` | string (8-77 chars) | sim | Chave Pix de destino | | `pixKeyType` | enum | não | `CPF` (default), `CNPJ`, `EMAIL`, `PHONE`, `RANDOM` | Response (atenção: `amount` em REAIS, ao contrário dos outros endpoints): ```json { "id": 9876, "amount": 500.00, "pixKey": "cpf_do_seller", "status": "PENDING", "createdAt": "2026-06-18T14:30:00Z" } ``` Erros: `400` amount fora de 20-10000 (respeite os limites service-side); `400` pixKey com menos de 8 ou mais de 77 caracteres; `422` saldo insuficiente (consulte o saldo antes). Gotcha: o schema aceita 1-100000, mas o service aplica 20-10000 — use os limites service-side. --- ## Rate limits A API aplica limites de requisição por endpoint (configuração padrão de produção): | Endpoint(s) | Limite padrão | Janela | |---|---|---| | `POST /api/sales` | ~30.000 req/min (~500 req/s) | 1 minuto | | Checkout público | ~3.000 req/min | 1 minuto | | `POST /api/apikey/regenerate/:publicKey` | 3 tentativas | 1 hora | | Demais endpoints autenticados | Limite padrão | 1 minuto | Quando o limite é atingido, a API retorna `HTTP 429 Too Many Requests`: ```json { "statusCode": 429, "message": "Too Many Requests" } ``` Boas práticas: em lançamentos (muitas vendas simultâneas) a criação de vendas suporta picos de ~500 req/s por padrão; implemente retry com backoff exponencial para 429; para limites maiores, contate o suporte. --- ## Erros Formato padronizado. O campo `code` é opcional e aparece quando o erro tem um código semântico; `details` aparece em erros de validação de campos. ```json { "statusCode": 422, "code": "INVALID_INSTALLMENT_PLAN", "message": "Plano de parcelamento inválido", "details": {} } ``` Catálogo de erros: | HTTP | code | Causa | |---|---|---| | 400 | `INVALID_JSON` | Body da requisição não é JSON válido | | 400 | `SALE_VALIDATION` | Campo de venda obrigatório ausente/inválido (veja `fieldErrors`/`details`) | | 400 | `PAYMENT_FAILED` | Não foi possível gerar a cobrança. Causas: faltou `customer.document` (CPF/CNPJ obrigatório p/ PIX) ou seller sem adquirente ativo — não é erro de schema | | 400 | (sem code) | Erro de validação de campo. O array `details` contém a lista de erros | | 401 | `UNAUTHORIZED` | Chaves de API ausentes, inválidas ou expiradas (ou só uma das duas enviada) | | 403 | `CROSS_TENANT_ATTEMPT_BLOCKED` | Recurso de outro seller em gateway mode. Use processor mode + `productOwnerExternalId` | | 404 | (sem code) | Registro não encontrado (ou de outro seller — ownership-scoped) | | 409 | (sem code) | Conflito — registro duplicado ou violação de unicidade | | 422 | `CURRENCY_NOT_SUPPORTED` | Moeda não disponível para este adquirente | | 422 | `INSTALLMENTS_NOT_SUPPORTED` | Parcelamento não habilitado para este vendedor | | 422 | `INVALID_INSTALLMENT_PLAN` | Número de parcelas ou valor incompatível com a configuração do vendedor | | 429 | (sem code) | Rate limit atingido. Aguarde e tente novamente com backoff | | 500 | (sem code) | Erro interno — reporte ao suporte com o timestamp da requisição | Erros de validação (HTTP 400) incluem um array `details` com os erros por campo: ```json { "statusCode": 400, "message": "amount must be a positive number", "details": [ { "field": "amount", "constraints": { "isPositive": "amount must be a positive number" } }, { "field": "customer.email", "constraints": { "isEmail": "email must be an email" } } ] } ```