Skip to main content
All use cases
Post-sale operationsOperations

A refund that can only go back where the money came from.

The customer complains in the support chat. The agent finds the payment's endToEndId and asks CodeSpar to return the Pix: the money goes back to the original payer, and the refund can never be more than what is left to return of that payment. Each refund carries an idempotency key, so a retry is the same refund. The refund is not checked against a mandate or a cap; the original payment is its bound. Issuing a credit note and looking the order up in your ERP are your integration.

BeforeTicket → someone with bank access → manual transfer
AfterThe agent returns the Pix to its payer, bounded by the payment
Pix ↩
back to the payer, at most the original amount
Try it in the Sandbox
MD06
Return reason
User-requested return, the default code
≤
Bound
Never more than what is left to return of the original credit
idempotency_key
Same refund on retry
The idempotency key makes a retry the same refund
Pix ↩
Original payer
The money goes back to whoever paid, on the same rail
Illustrative example · demo data

The refund, from the chat.

An example with demo data: the customer asks for a refund in the support chat; the agent finds the Pix payment and asks CodeSpar to return it to the payer. The conversation is in Portuguese, as the customer wrote it.

  • The refund goes back to the original payer, on the same rail
  • Never more than what is left to return of the payment
  • Not checked against a mandate or a cap: the payment is the bound
Marina · pedido #8421
Suporte · Pix
Agent
Oi! O pedido #8421 veio errado, quero o estorno.
Encontrei o pagamento Pix de R$ 186,00 do pedido #8421. Devolvo para a mesma conta que pagou, ok?
Pode sim.
Devolução solicitada.
DevoluçãoR$ 186,00 · Pix
MotivoMD06
Idempotênciarefund-8421
via pix/devolutions · Celcoin
✓ devolução solicitada · exemplorefund-8421
The pain

The conversation is the easy part.

Refunds are where support meets money: the ticket waits for someone with bank access, the manual transfer does not match the original payment, and nobody can say later what was returned.

Escalate every refund to whoever holds the bank login

The agent returns the Pix through the API, with its own key

A manual transfer that does not match the original payment

The refund names the payment's endToEndId and goes back to its payer

Refund twice after a timeout

The idempotency key makes a retry the same refund

Refund more than was paid

The refund cannot exceed what is left to return of the payment

How the agent does it

A refund bounded by the payment.

The agent calls POST /v1/consumers/{consumerId}/pix/devolutions with the payment's end_to_end_id, the amount in centavos and an idempotency key; a GET on the devolution reads its status. The refund goes back to the original payer and is bounded by what is left to return of that credit. It does not consume a mandate. Looking the order up, issuing a credit note and telling the customer are your integration.

01
Ticket
Support chat

The customer asks for a refund

02
Find
Your order system

The payment's endToEndId

03
Refund
pix/devolutions

Pix back to the payer

04
Status
pix/devolutions

Read by id

05
Tell
Your integration

The customer, in the chat

Architecture

The ticket enters from your support channel. The agent resolves the order and its Pix payment in your systems, then calls the devolution route with the endToEndId. CodeSpar checks the payment against the consumer's own statement, refuses a second reversal of the same money, reverses the wallet entry and dispatches the return on Celcoin; its status is read on the same route. A mandate is not consumed: the return is pinned to the original payer and bounded by the original credit.

In code

The code, and what it assumes.

support-refund.ts
// Prerequisites: CODESPAR_API_KEY set to a test key (csk_test_…), a consumer
// (user_0000) whose wallet received the Pix, and that payment's endToEndId.
import { CodeSpar } from "@codespar/sdk";

const cs = new CodeSpar();

// return R$ 186.00 of the payment to its payer; never more than what is left to return
const res = await cs.api.response("post", "/v1/consumers/{consumerId}/pix/devolutions", {
  path: { consumerId: "user_0000" },
  body: { end_to_end_id: "E00000000202610081200abcdef123456", amount_minor: 18_600, idempotency_key: "refund-8421" },
});
console.log(res.status, res.ok ? res.data : null);

Example with the published SDK (@codespar/sdk 0.16.11). Its prerequisites are in the comments. Compiling does not prove the integration: run it in test mode first.

Featured tools
POST /v1/consumers/{consumerId}/pix/devolutions

Returns a received Pix to its payer by endToEndId, bounded by the original credit, with a required idempotency key.

GET /v1/consumers/{consumerId}/pix/devolutions/{devolutionId}

Reads the refund's status.

See the meta-tool reference
MCP servers wired

Start with a test key.

Test keys are free. Open the sandbox, connect the providers your project uses and see which tools it can call before you build.

Support refund agent — CodeSpar | CodeSpar