As recompensas permitem-lhe transformar parte de um pagamento em créditos que o cliente pode gastar num pagamento posterior. Os créditos ficam numa conta de recompensas associada ao seu marketplace e seguem o cliente que os ganhou apenas esse cliente os pode resgatar, e os créditos expiram após um período definido (12 meses por defeito).
O fluxo tem dois lados. Gera recompensas anexando um bloco reward a um ou mais splits dentro de uma captura. Resgata-as mais tarde enviando um bloco reward_redemption na captura seguinte. Entre essas duas operações, pode consultar o que cada cliente tem disponível através dos endpoints de Customer. E se um pagamento for reembolsado, as suas recompensas são revertidas a secção Reverter um pagamento que usou recompensas, mais abaixo, explica isto em detalhe.
A conta de recompensas é por marketplace. É provisionada na configuração inicial não existe API para a criar e é referenciada pelo seu UUID em cada geração e resgate de recompensa.
Cada entrada numa conta de recompensas está associada a um cliente. Quando um pagamento inclui um split com um bloco reward, o cliente identificado no topo do pedido é creditado pelo valor em reward.value. Esse crédito passa a fazer parte do saldo disponível do cliente até ser resgatado ou expirar.
O resgate funciona no sentido inverso: numa captura posterior para o mesmo cliente, envia um bloco reward_redemption e o valor correspondente é debitado do saldo e aplicado ao pagamento.
Anexe um bloco reward a qualquer split dentro do array capture.splits[]. O cliente identificado no topo do pedido é o que recebe o crédito.
curl -X POST 'https://api.test.easypay.pt/2.0/single' \
-H 'AccountId: SEU_ACCOUNT_ID' \
-H 'ApiKey: SUA_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"type": "sale",
"method": "cc",
"value": 50.00,
"currency": "EUR",
"customer": {
"id": "649e88cf-0b78-4c36-8f99-33f5ebb812a1",
"name": "John Doe",
"email": "john.doe@example.com"
},
"capture": {
"descriptive": "Order #1029",
"splits": [
{
"split_descriptive": "Marketplace seller",
"account": {
"id": "7e697e0c-c2bf-422a-9535-ab0b750bb832"
},
"value": 50.00,
"reward": {
"account": {
"id": "458b2fc4-3092-4de3-abd4-fe1600c09420"
},
"value": 2.50,
"expiration_date": "2027-04-02"
}
}
]
}
}'O que cada campo de reward faz:
reward.account.id: a conta de recompensas do marketplace que detém o crédito. Use o mesmo UUID em todas as recompensas que pretende agregar no mesmo saldo.reward.value: quanto desse split se transforma em crédito. Não altera o que o cliente paga no momento; é um valor que o marketplace contribui a partir do valor do split.reward.expiration_date: opcional. Por defeito são 12 meses a partir da data da transação, e não pode ser definida para além do máximo de um ano. Depois desta data o crédito já não pode ser resgatado.
Dois endpoints expõem o que um cliente tem.
GET /customer/{id} devolve o cliente juntamente com um array reward_balances com uma entrada por cada conta de recompensas em que tem créditos. Este é o saldo disponível autoritativo reflete resgates, reembolsos e reversões. Use-o quando quiser um total rápido antes de apresentar uma opção "Usar as suas recompensas" no checkout.
{
"id": "649e88cf-0b78-4c36-8f99-33f5ebb812a1",
"name": "John Doe",
"email": "john.doe@example.com",
"reward_balances": [
{
"account_id": "458b2fc4-3092-4de3-abd4-fe1600c09420",
"available_balance": 12.5
}
]
}GET /customer/{id}/rewards lista todos os movimentos individuais no histórico, do mais recente para o mais antigo. Suporta filtragem por conta, tipo, expiração e data de criação. Cada movimento tem um type:
REWARD: foi ganho um crédito.REDEMPTION: um crédito foi gasto num pagamento.REWARD_EXPIRATION: um crédito expirou.REWARD_REVERSAL: um crédito ganho foi recuperado (o pagamento que o gerou foi reembolsado).REWARD_RESTORATION: um crédito gasto foi devolvido (um resgate foi revertido).
curl 'https://api.test.easypay.pt/2.0/customer/649e88cf-0b78-4c36-8f99-33f5ebb812a1/rewards?type[]=REWARD&account_id[]=458b2fc4-3092-4de3-abd4-fe1600c09420' \
-H 'AccountId: SEU_ACCOUNT_ID' \
-H 'ApiKey: SUA_API_KEY'{
"metadata": { "next_cursor": null, "count": 2 },
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"account_id": "458b2fc4-3092-4de3-abd4-fe1600c09420",
"type": "REWARD",
"amount": 10.0,
"expiration_date": "2027-01-15",
"capture": { "id": "c6056234-a3f9-42de-b944-3ed793fcb6bb" },
"created_at": "2026-01-15T10:30:00Z"
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"account_id": "458b2fc4-3092-4de3-abd4-fe1600c09420",
"type": "REWARD",
"amount": 2.5,
"expiration_date": "2027-04-02",
"capture": { "id": "b6f53027-0478-4728-9269-8bcc0f8088ea" },
"created_at": "2026-04-02T09:12:00Z"
}
]
}Use o histórico quando precisar de um registo de auditoria por movimento por exemplo, quando um cliente pergunta de onde veio um determinado crédito, ou quando quer avisar sobre créditos prestes a expirar. Para o total disponível atual, prefira GET /customer/{id} é o valor real e atualizado.
Para gastar créditos, adicione um bloco reward_redemption à captura que está a pagar.
A localização do bloco depende do endpoint:
POST /single(pagamento num único passo) o bloco fica dentro do objetocapture:capture.reward_redemption.POST /capture/{id}(captura de uma autorização anterior) o bloco fica na raiz do corpo da captura:reward_redemption.
O resgate é por conta de recompensas: um bloco reward_redemption aponta para um UUID de conta. O valor resgatado não pode exceder o saldo disponível nessa conta, nem o valor do próprio pagamento.
Resgate parcial em POST /single aplicar apenas parte do saldo:
{
"type": "sale",
"method": "CC",
"value": 50.0,
"customer": {
"id": "649e88cf-0b78-4c36-8f99-33f5ebb812a1"
},
"capture": {
"reward_redemption": {
"account": {
"id": "458b2fc4-3092-4de3-abd4-fe1600c09420"
},
"value": 5.0
}
}
}Resgate total em POST /single aplicar todo o valor do pagamento:
{
"type": "sale",
"method": "CC",
"value": 50.0,
"customer": {
"id": "649e88cf-0b78-4c36-8f99-33f5ebb812a1"
},
"capture": {
"reward_redemption": {
"account": {
"id": "458b2fc4-3092-4de3-abd4-fe1600c09420"
},
"value": 50.0
}
}
}O value que envia é o bruto o valor antes das recompensas. O cliente é cobrado por value − reward_redemption.value através do método de pagamento escolhido (o valor de rails); a parte resgatada é coberta pelo saldo. O valor resgatado é debitado do saldo imediatamente e aparece como uma entrada REDEMPTION no histórico.
Quando o resgate iguala o valor total do pagamento (resgate total), o valor de rails é 0: nada é cobrado no gateway de pagamento e o pagamento é concluído na criação com payment_status = paid.
Um único pagamento pode fazer ambos. Em POST /single, o bloco reward_redemption fica dentro de capture e reduz o valor que o cliente paga; os blocos capture.splits[].reward creditam o cliente com base nos splits. Não interagem entre si pode resgatar €10 de um saldo anterior e ganhar €5 de novos créditos na mesma captura.
O exemplo Sale with Splits and Reward Redemption em POST /single mostra a forma combinada de ponta a ponta.
Os créditos que um cliente nunca gasta não ficam indefinidamente. Um processo agendado encontra os créditos cuja data de expiração já passou e que ainda têm saldo positivo, marca-os como expirados (saldo disponível → 0) e paga o valor remanescente da conta de recompensas para a conta de payout do marketplace. A partir desse momento o cliente já não pode gastar o crédito, e o movimento aparece como REWARD_EXPIRATION no histórico do cliente.
Quando reembolsa uma captura que tinha recompensas, também é preciso revertê-las os créditos ganhos são recuperados, e qualquer cashback resgatado é devolvido ao cliente. Controla isto através de um bloco revert no reembolso.
Um reembolso com um bloco revert tem três partes:
valueo bruto que está a reverter (rails + qualquer cashback resgatado). O valor de rails efetivamente devolvido e o cashback restaurado são derivados a partir deste e do campo de reversão abaixo.revert.modeouTOTAL(reverter a captura inteira) ouPARTIAL(reverter splits específicos).revert.reward_redemption_reversal(opcional) quanto do cashback resgatado devolver ao saldo do cliente neste reembolso. O valor de rails devolvido ao pagador évalue − reward_redemption_reversal.
Uma reversão TOTAL reverte todos os splits da captura. O value tem de ser igual ao bruto da captura. Se omitir reward_redemption_reversal, este assume por defeito o resgate remanescente (todo o cashback ainda não restaurado por um reembolso anterior), e o valor de rails devolvido é o restante.
{
"value": 50.0,
"revert": {
"mode": "TOTAL"
}
}Uma reversão PARTIAL visa um ou mais splits por id. O value tem de ser igual à soma do bruto dos splits visados. O reward_redemption_reversal é um valor livre à sua escolha, retirado da pool de resgate da captura não está ligado à quota proporcional do split visado, pelo que uma única reversão parcial pode restaurar todo o resgate, se assim o pretender.
{
"value": 12.0,
"revert": {
"mode": "PARTIAL",
"reward_redemption_reversal": 5.0,
"splits": [{ "id": "3f2a9c10-7b4e-4d21-9a55-0c1e2f3a4b5c" }]
}
}Aqui, €12 de bruto são revertidos no split visado, €5 de cashback são restaurados ao saldo do cliente, e 12 − 5 = €7 de valor de rails são devolvidos ao pagador.
O reward_redemption_reversal restaura cashback a partir de uma pool partilhada o total resgatado na captura, menos o que reembolsos anteriores já restauraram. Ao longo de uma sequência de reembolsos parciais nunca pode restaurar mais do que o que foi originalmente resgatado. Quando restaura cashback, este volta ao saldo disponível do cliente imediatamente (visível em GET /customer/{id}) como um movimento REWARD_RESTORATION, e os créditos ganhos em qualquer split revertido são recuperados como REWARD_REVERSAL.
Se a verificação de saldo do comerciante estiver ativa para o seu cliente (SPLIT_REFUND_BALANCE_CHECK_ENABLED), uma reversão só é aceite quando as contas a debitar têm saldo suficiente para a cobrir. Se não tiverem, a reversão é recusada (HTTP 412) com refund value can not exceed the balance of the debited accounts, try again later tente novamente quando o saldo estiver disponível.
As reversões devolvem HTTP 412 com uma destas mensagens quando uma regra é violada:
revert.reward_redemption_reversal cannot be negative: a reversão é inferior a 0.revert.reward_redemption_reversal: the capture has no reward redemption to revert: enviou uma reversão mas a captura nunca resgatou.revert.reward_redemption_reversal cannot exceed the refund value: a reversão é superior aovalue.revert.reward_redemption_reversal exceeds the remaining redemption (X.XX): a reversão é superior ao cashback ainda disponível na pool.revert.reward_redemption_reversal must equal the remaining redemption (X.XX) on a TOTAL revert: numa reversão TOTAL a reversão não é livre; tem de esgotar todo o resgate remanescente.revert.splits: the value of the splits to revert X.XX is different than the requested refund value V: numa reversão PARTIAL, ovaluenão corresponde ao bruto dos splits visados.the rails refund (X.XX) exceeds the remaining refundable rails value (Y.XX): o valor de rails (value − reversal) excede o que ainda é reembolsável.revert_mode TOTAL is not supported for partial refund: TOTAL enviado com umvalueinferior ao bruto da captura.revert.mode PARTIAL requires at least one split id to be specified: PARTIAL enviado semrevert.splits.
Para consultar exatamente o que uma reversão restaurou, GET /refund/{id} expõe o objeto reward_redemption_reversal com value (restaurado neste reembolso) e value_remaining (cashback ainda restaurável na captura), juntamente com os objetos reward_redemption e reward (por split) da captura associada. GET /capture/{id} expõe igualmente o reward_redemption da captura e o reward de cada split.
- Endpoints de Customer: referência de saldo e histórico
- Single Payment: ganhar e resgatar num único passo
- Captures: ganhar e resgatar numa captura separada
- Refunds: reverter um pagamento que usou recompensas
- Autorizações e Capturas: quando separar autorização e captura