API v1 S2S StableServer-to-ServerLive + SandboxDocumentação pública

Integração de pagamentos XPaymentsAPI S2S

Guia técnico para integrar MB WAY, Bizum, Multibanco, Bancontact e BLIK pelo backend do Merchant.

Endpoint base
https://api.xpayments.digital/api/v1

Criar pagamento

POST /payments/charge

Auth

Bearer xp_...

01 · Quickstart

Do zero ao primeiro PaymentIntent

A integração é backend-only. A API Key identifica uma Store XPayments e define o ambiente e permissões disponíveis.

Passo 1

Obter API Key

Crie uma chave da Store com payments_write.

Passo 2

POST charge

Envie amount em unidade mínima e uma reference única.

Passo 3

Tratar action

bank_app, redirect ou referência Multibanco.

Passo 4

Receber webhook

Use o evento para atualizar o pedido no seu sistema.

Passo 5

Confirmar sucesso

Só payment_intent.succeeded confirma financeiramente.

cURL · Sandbox MB WAY
curl -X POST \
  https://api.xpayments.digital/api/v1/payments/charge \
  -H "Authorization: Bearer xp_test_xxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500,
    "currency": "EUR",
    "payment_method_types": ["mb_way"],
    "reference": "ACME-PT-20260905-0001",
    "customer": {
      "name": "Cliente Sandbox",
      "phone": "+351911111112"
    },
    "metadata": {
      "order_id": "ACME-PT-20260905-0001"
    }
  }'
Node.js · exemplo genérico
const response = await fetch(
  "https://api.xpayments.digital/api/v1/payments/charge",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.XPAYMENTS_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: 500,
      currency: "EUR",
      payment_method_types: ["mb_way"],
      reference: "ACME-PT-20260905-0001",
      customer: { name: "Cliente Exemplo", phone: "+351912345678" },
      metadata: { order_id: "ACME-PT-20260905-0001" },
    }),
  }
);

const payment = await response.json();
if (!response.ok) throw new Error(payment?.error?.code ?? "PAYMENT_ERROR");

// requires_action não significa pago.
// A confirmação financeira definitiva chega pelo webhook.
console.log(payment);

02 · Credenciais

Criar e gerir uma API Key

Cada API Key pertence a uma Store. Use chaves diferentes por Store e por ambiente.

  1. 01No Dashboard XPayments abra API Keys.
  2. 02Clique Create API key e selecione a Store correta.
  3. 03Selecione Test ou Live.
  4. 04Ative payments_write.
  5. 05Guarde a chave num secret manager ou variável de ambiente do servidor.
  6. 06Em caso de exposição, use Revoke e gere outra.

Headers suportados

Authorization: Bearer xp_live_********************************

x-api-key: xp_live_******************************** (compatibilidade)

API Keys

Prévia sanitizada do Dashboard · dados fictícios

+ Create API key

Store

ACME Portugal

ACME-PT-ORCH

Environment

Live

Key

xp_live_a12b••••9f30

Scopes

payments_write
Chaves XPAYMENTS não são chaves Stripe. Nunca envie sk_live_ ou sk_test_ ao Merchant.

03 · Payment Methods

Exemplos por meio de pagamento

Todos os exemplos usam POST /payments/charge. amount é inteiro na menor unidade monetária: 500 EUR = €5,00; 500 PLN = zł5,00.

MétodoMoedaFluxoObrigatório
MB WAYEURbank_appTelefone
BizumEURbank_appTelefone espanhol
MultibancoEURmultibanco_referenceEmail
BancontactEURredirectNome + return_url HTTPS
BLIKPLNbank_appCódigo de 6 dígitos

MB WAY

Telefone válido. Recomendado em formato internacional, por exemplo +351912345678.

EUR · bank_app
MB WAY · request body
{
  "amount": 500,
  "currency": "EUR",
  "payment_method_types": ["mb_way"],
  "reference": "ACME-MBWAY-20260905-0001",
  "customer": { "name": "Cliente Exemplo", "phone": "+351912345678" },
  "metadata": { "order_id": "ACME-MBWAY-20260905-0001" }
}
MB WAY · resposta típica
{
  "success": true,
  "transactionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "reference": "ACME-MBWAY-20260905-0001",
  "providerId": "pi_...",
  "status": "requires_action",
  "method": "mb_way",
  "action": {
    "type": "bank_app",
    "message": "Pedido MB WAY enviado. Confirme na aplicação."
  }
}
O cliente aprova na aplicação MB WAY. Só considere o pagamento concluído depois de payment_intent.succeeded.

Bizum

Telefone espanhol válido (+34...). O runtime XPayments aceita Bizum em EUR e aplica os limites configurados da Store.

EUR · bank_app
Bizum · request body
{
  "amount": 500,
  "currency": "EUR",
  "payment_method_types": ["bizum"],
  "reference": "ACME-BIZUM-20260905-0001",
  "customer": { "name": "Cliente Exemplo", "phone": "+34612345678" },
  "metadata": {
    "order_id": "ACME-BIZUM-20260905-0001",
    "return_url": "https://merchant.example/payments/result"
  }
}
Bizum · resposta típica
{
  "success": true,
  "transactionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "reference": "ACME-BIZUM-20260905-0001",
  "providerId": "pi_...",
  "status": "requires_action",
  "method": "bizum",
  "action": {
    "type": "bank_app",
    "message": "Pedido Bizum enviado. Confirme na aplicação do seu banco."
  }
}
O comprador confirma no banco. Não use dados Sandbox numa Store Live.

Multibanco

Email do cliente. A resposta devolve Entidade, Referência e Montante.

EUR · reference
Multibanco · request body
{
  "amount": 500,
  "currency": "EUR",
  "payment_method_types": ["multibanco"],
  "reference": "ACME-MB-20260905-0001",
  "customer": { "name": "Cliente Exemplo", "email": "cliente@example.com" },
  "metadata": { "order_id": "ACME-MB-20260905-0001" }
}
Multibanco · resposta típica
{
  "success": true,
  "transactionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "reference": "ACME-MB-20260905-0001",
  "providerId": "pi_...",
  "status": "requires_action",
  "method": "multibanco",
  "action": {
    "type": "multibanco_reference",
    "entidade": "12345",
    "referencia": "123456789",
    "montante": "5.00 EUR"
  }
}
Mostre os três campos ao cliente e aguarde o webhook final. A geração da referência não significa pagamento.

Bancontact

customer.name e metadata.return_url HTTPS. Abra o redirect no browser principal, não em iframe.

EUR · redirect
Bancontact · request body
{
  "amount": 500,
  "currency": "EUR",
  "payment_method_types": ["bancontact"],
  "reference": "ACME-BE-20260905-0001",
  "customer": { "name": "Pieter Janssen", "email": "cliente@example.com" },
  "metadata": {
    "order_id": "ACME-BE-20260905-0001",
    "return_url": "https://merchant.example/payments/result"
  }
}
Bancontact · resposta típica
{
  "success": true,
  "transactionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "reference": "ACME-BE-20260905-0001",
  "providerId": "pi_...",
  "status": "requires_action",
  "method": "bancontact",
  "action": { "type": "redirect", "url": "https://..." }
}
O retorno ao return_url é UX. A confirmação financeira continua a ser o webhook.

BLIK

PLN e código BLIK de 6 dígitos. O código é temporário e não deve ser persistido ou registado em logs.

PLN · bank_app
BLIK · request body
{
  "amount": 500,
  "currency": "PLN",
  "payment_method_types": ["blik"],
  "reference": "ACME-PL-20260905-0001",
  "customer": { "name": "Jan Kowalski", "email": "cliente@example.com" },
  "payment_method_options": { "blik": { "code": "123456" } },
  "metadata": { "order_id": "ACME-PL-20260905-0001" }
}
BLIK · resposta típica
{
  "success": true,
  "transactionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "reference": "ACME-PL-20260905-0001",
  "providerId": "pi_...",
  "status": "requires_action",
  "method": "blik",
  "action": {
    "type": "bank_app",
    "message": "Confirme o pagamento BLIK na aplicação do seu banco.",
    "expiresInSeconds": 60
  }
}
O cliente tem 60 segundos para autorizar depois de iniciar o pagamento. Envie o código ao XPayments imediatamente.

04 · Sandbox

Dados de teste

Use estes valores apenas com uma Store Test/Sandbox (xp_test_...) ligada a provider Test. Em Live, os simuladores não reproduzem estes cenários.

MB WAY

+351911111112Sucesso após requires_action
+351911111113payment_method_not_available
+351911111114payment_method_provider_decline
+351911111115payment_intent_payment_attempt_expired
+351911111116payment_method_customer_decline
Stripe MB WAY testing

Multibanco

succeed_immediately@example.com

Sucesso em poucos segundos

expire_immediately@example.com

Expira imediatamente

expire_with_delay@example.com

Falha após atraso de teste

fill_never@example.com

Simula referência nunca paga

Stripe Multibanco testing

BLIK

Em Sandbox, use um código de 6 dígitos como 123456. O cliente confirma depois no banco.

Stripe BLIK testing

Bizum / Bancontact

A documentação pública atual da Stripe não apresenta uma tabela fixa de números Bizum equivalente à do MB WAY. Use apenas os dados fornecidos para a sua Store Sandbox. Para Bancontact, siga o redirect gerado em Test e confirme pelo webhook.

05 · Webhooks

Receber o estado definitivo

Configure um endpoint HTTPS por Store ORCHESTRATED para receber XPayments → Merchant. Estes endpoints são separados dos webhooks Stripe internos.

Configuração no Dashboard

  1. 1. Abra Webhooks & API.
  2. 2. Em Merchant Delivery · ORCHESTRATED, clique Novo endpoint Merchant.
  3. 3. Selecione a Store e introduza uma URL HTTPS.
  4. 4. Ative os quatro eventos suportados.
  5. 5. Guarde o signing secret e valide o header em cada chamada.
Eventos Merchant
payment_intent.succeeded
payment_intent.payment_failed
payment_intent.processing
payment_intent.canceled
Payload
{
  "event": "payment_intent.succeeded",
  "transaction_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "reference": "ACME-PT-20260905-0001",
  "amount": 5,
  "currency": "EUR",
  "status": "succeeded",
  "method": "mb_way",
  "timestamp": "2026-09-05T16:00:00.000Z"
}

Merchant Delivery · ORCHESTRATED

Prévia sanitizada · dados fictícios

+ Novo endpoint Merchant
ACME PortugalACME-PT-ORCHactive

https://api.merchant.example/webhooks/xpayments

succeededfailedprocessingcanceled

Assinatura: x-nexflowx-signature · HMAC-SHA256

Node.js · validar assinatura
import crypto from "node:crypto";

export function verifyXPaymentsWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  const a = Buffer.from(signature ?? "", "utf8");
  const b = Buffer.from(expected, "utf8");

  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

amount no webhook

No request: 500 EUR. No webhook: 5 EUR.

Idempotência

Deduplique por event + transaction_id e responda HTTP 2xx rapidamente.

Confirmação

Nunca confirme pedido por redirect ou requires_action. Use payment_intent.succeeded.

06 · Erros

Respostas que o integrador deve tratar

HTTPcodeSignificado
401API_KEY_REQUIRED / ACCESS_DENIEDChave ausente, inválida ou Store inativa.
403INSUFFICIENT_SCOPEA chave não possui payments_write.
400INVALID_AMOUNT / INVALID_CURRENCYPayload inválido.
400INVALID_MBWAY_PHONE / INVALID_BIZUM_PHONETelefone fora do formato aceite.
400BIZUM_EUR_REQUIRED / BIZUM_AMOUNT_OUT_OF_RANGERegra específica do Bizum.
400GATEWAY_NOT_CONFIGUREDA Store não possui provider configurado para o método.
409TRANSACTION_ALREADY_PAIDA reference já corresponde a uma transação succeeded.
409LIVE_KEY_TEST_GATEWAY_MISMATCHChave Live ligada a provider Test.
409TEST_KEY_LIVE_GATEWAY_MISMATCHChave Test ligada a provider Live.
402PAYMENT_FAILED / provider errorO provider recusou ou não autorizou o pagamento.

07 · Produção

Checklist antes do go-live

API Key server-side

Nunca exponha xp_live_ ou xp_test_ no browser, mobile app ou repositório público.

Scope correto

POST /payments/charge exige payments_write.

Unidade monetária

Envie amount em cêntimos/centavos ou unidade mínima da moeda.

Reference única

Use referência forte e namespaced, por exemplo ACME-PT-20260905-0001.

Webhook validado

Use HTTPS, HMAC-SHA256 e idempotência no endpoint Merchant.

Separar Test e Live

xp_test_ deve usar provider Test; xp_live_ deve usar provider Live.

Fluxo recomendado

Comece numa Store Sandbox e mova o mesmo contrato para uma Store Live após validação.

Voltar ao Quickstart