Refund one transaction
curl -s -X POST "https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund" \ -H "authorization: Bearer $ACCESS_TOKEN" \ -H "idempotency-key: refund-EP-123456-01" \ -H "content-type: application/json" \ -d '{ "amount": 2500, "extraData": "EP-123456 partial refund"}'const response = await fetch("https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund", { method: "POST", headers: { authorization: `Bearer ${accessToken}`, "idempotency-key": "refund-EP-123456-01", "content-type": "application/json" }, body: JSON.stringify({ amount: 2500, extraData: "EP-123456 partial refund", }),});var response = client.send( HttpRequest.newBuilder(URI.create("https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund")) .header("authorization", "Bearer " + accessToken) .header("idempotency-key", "refund-EP-123456-01") .header("content-type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(Map.of( "amount", 2500, "extraData", "EP-123456 partial refund")))) .build(), HttpResponse.BodyHandlers.ofString());var request = new HttpRequestMessage(HttpMethod.Post, "https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund");request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);request.Headers.Add("idempotency-key", "refund-EP-123456-01");request.Content = JsonContent.Create(new{ amount = 2500, extraData = "EP-123456 partial refund",});var response = await http.SendAsync(request);$request = curl_init("https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund");curl_setopt_array($request, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "authorization: Bearer $accessToken", 'idempotency-key: refund-EP-123456-01', 'content-type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'amount' => 2500, 'extraData' => 'EP-123456 partial refund', ]),]);$response = curl_exec($request);response = requests.post( "https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund", headers={"authorization": f"Bearer {access_token}", "idempotency-key": "refund-EP-123456-01"}, json={ "amount": 2500, "extraData": "EP-123456 partial refund", },)uri = URI("https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund")request = Net::HTTP::Post.new(uri)request["authorization"] = "Bearer #{access_token}"request["idempotency-key"] = "refund-EP-123456-01"request["content-type"] = "application/json"request.body = { amount: 2500, extraData: "EP-123456 partial refund"}.to_jsonresponse = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }body, err := json.Marshal(map[string]any{ "amount": 2500, "extraData": "EP-123456 partial refund",})if err != nil { return err}req, err := http.NewRequest("POST", "https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund", bytes.NewReader(body))if err != nil { return err}req.Header.Set("authorization", "Bearer "+accessToken)req.Header.Set("idempotency-key", "refund-EP-123456-01")req.Header.Set("content-type", "application/json")resp, err := http.DefaultClient.Do(req)if err != nil { return err}defer resp.Body.Close()let response = http .post("https://services.sandbox.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund") .bearer_auth(access_token) .header("idempotency-key", "refund-EP-123456-01") .json(&json!({ "amount": 2500, "extraData": "EP-123456 partial refund" })) .send() .await?;curl -s -X POST "https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund" \ -H "authorization: Bearer $ACCESS_TOKEN" \ -H "idempotency-key: refund-EP-123456-01" \ -H "content-type: application/json" \ -d '{ "amount": 2500, "extraData": "EP-123456 partial refund"}'const response = await fetch("https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund", { method: "POST", headers: { authorization: `Bearer ${accessToken}`, "idempotency-key": "refund-EP-123456-01", "content-type": "application/json" }, body: JSON.stringify({ amount: 2500, extraData: "EP-123456 partial refund", }),});var response = client.send( HttpRequest.newBuilder(URI.create("https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund")) .header("authorization", "Bearer " + accessToken) .header("idempotency-key", "refund-EP-123456-01") .header("content-type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(Map.of( "amount", 2500, "extraData", "EP-123456 partial refund")))) .build(), HttpResponse.BodyHandlers.ofString());var request = new HttpRequestMessage(HttpMethod.Post, "https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund");request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);request.Headers.Add("idempotency-key", "refund-EP-123456-01");request.Content = JsonContent.Create(new{ amount = 2500, extraData = "EP-123456 partial refund",});var response = await http.SendAsync(request);$request = curl_init("https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund");curl_setopt_array($request, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "authorization: Bearer $accessToken", 'idempotency-key: refund-EP-123456-01', 'content-type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'amount' => 2500, 'extraData' => 'EP-123456 partial refund', ]),]);$response = curl_exec($request);response = requests.post( "https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund", headers={"authorization": f"Bearer {access_token}", "idempotency-key": "refund-EP-123456-01"}, json={ "amount": 2500, "extraData": "EP-123456 partial refund", },)uri = URI("https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund")request = Net::HTTP::Post.new(uri)request["authorization"] = "Bearer #{access_token}"request["idempotency-key"] = "refund-EP-123456-01"request["content-type"] = "application/json"request.body = { amount: 2500, extraData: "EP-123456 partial refund"}.to_jsonresponse = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }body, err := json.Marshal(map[string]any{ "amount": 2500, "extraData": "EP-123456 partial refund",})if err != nil { return err}req, err := http.NewRequest("POST", "https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund", bytes.NewReader(body))if err != nil { return err}req.Header.Set("authorization", "Bearer "+accessToken)req.Header.Set("idempotency-key", "refund-EP-123456-01")req.Header.Set("content-type", "application/json")resp, err := http.DefaultClient.Do(req)if err != nil { return err}defer resp.Body.Close()let response = http .post("https://services.payplug-elements.msem.tech/api/transactions/0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9d/refund") .bearer_auth(access_token) .header("idempotency-key", "refund-EP-123456-01") .json(&json!({ "amount": 2500, "extraData": "EP-123456 partial refund" })) .send() .await?;Point at the operation that TOOK the money (the attempt’s capture, or its direct payment — or a later debit, refunded against its own amount). amount absent refunds everything that remains refundable of it; a slice needs the method’s contract to carry partial refunds. Post-terminal only (the payer flow never refunds), cumulative, one refund in flight per attempt.
Authorizations
Section titled “Authorizations”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters”The PSP operation, as a search returned it. A lowercase UUID — the ones we mint are v7.
Example
0193f6c1-9c40-7d6f-b123-4e5f6a7b8c9dHeader Parameters
Section titled “Header Parameters”Makes the gesture replayable: a retry presenting a key already recorded on this attempt gets the recorded refund back — never a second one. Recommended whenever amount travels; optional (full refunds converge on their own).
Example
refund-EP-123456-01Request Bodyrequired
Section titled “Request Bodyrequired”Send {} (or omit amount) for a full refund of what remains.
Send {} (or omit amount) for a full refund of what remains.
object
Minor units to give back — a slice, when the method’s contract refunds partially. Absent: everything that remains refundable on the attempt.
Example
2500Your reconciliation tag for THIS refund — echoed in the PSP’s reporting where supported, and back on the refund transaction here.
Example
EP-123456 partial refundResponses
Section titled “ Responses ”The refund operations this gesture produced — read each status: succeeded or failed when the PSP decided on the spot, pending while it has not. Every verdict also reaches you in the refund webhook.
object
The refund operations this call started, with the attempt and session each belongs to.
The transaction, with the home that gives it meaning — session, order, attempt.
object
The session this belongs to.
The merchant it belongs to.
Their own order reference.
The attempt it belongs to.
What the attempt behind this operation was paid with — card, paypal, wero… An operation alone does not say it, and reading a list of PSP operations without it means opening each one.
The card network that attempt ran on, when the PSP named one we could place — see the same field on an attempt.
The card as the PSP masked it — see the same field on an attempt.
The country of the card’s issuer — see the same field on an attempt.
The PSP adapter that served the attempt (D-051) — whose dashboard the references live in.
The operation itself.
object
Our handle for this PSP operation — what a refund door addresses.
When the operation was opened — epoch milliseconds (Q13).
The last event that touched it — for a terminal transaction, its verdict’s instant.
What this operation asked the PSP: hold the money, take it in one go, capture a hold, release a hold, send money back, or debit the registered card later.
What this operation moved, in minor units.
object
Amount in the MINOR unit of the currency — 1000_00 is one thousand euros, never 1000.
ISO 4217 code, uppercase. One currency per session.
The PSP’s reference — what their dashboard greps (D-047).
The VERDICT facet: what the PSP finally decided about this operation — as opposed to the ack facet below, which is what the driving call answered on the spot.
object
Where the operation stands. pending means the verdict is still due — it always arrives out-of-band.
The PSP’s own code, split at the source — successes carry theirs too.
The PSP’s own sentence, as they said it — never glued to the code.
What a refusal means, when the PSP’s answer could be read.
What the driving call answered (the ack facet).
What the driving call said — a transport failure’s raw cause included.
Absent beside a present ackMessage = no HTTP response ever came.
The PSP’s own reference for the driving call’s exchange, when it named one — what its support asks for.
The caller’s reconciliation tag, on refunds only (lot 5) — echoed verbatim.
The refused operation this one replays — asked again by an administrator.
On a refund: the later debit it gives back — absent, the attempt’s own taking.
Example
{ "refunds": [ { "method": "card", "cardScheme": "visa", "cardCode": "497010XXXXXX0007", "cardCountry": "FR", "provider": "dalenys", "transaction": { "type": "authorization", "status": { "kind": "pending", "category": "bank-refusal" } } } ]}InvalidRequest — the request could not be read: a missing or malformed field, a bad pattern, or a property this door does not declare (the message names it). Every door with a schema can answer this, before any business rule is consulted. Most often here: InvalidRequestedAmount — the DOMAIN’s own refusal of a refund amount that is not a positive number of minor units (REFUND_STATUS), raised after validation has passed. Unreachable through this door as it stands: the schema bounds amount, and an omitted one resolves to what remains refundable. Declared because the code can answer it — a contract that hides a possible answer is the one that surprises.
object
Stable machine-readable code — the one thing to branch on. Never parse the message.
English sentence for logs and operators. Wording may change; the code will not.
Example
{ "code": "InvalidRequestedAmount", "message": "the refund amount cannot be used"}Unauthorized — the only code this response carries: no usable access token (absent, malformed, expired). One answer for every failure shape, so nothing can be learned by watching which one comes back.
object
Stable machine-readable code — the one thing to branch on. Never parse the message.
English sentence for logs and operators. Wording may change; the code will not.
Example
{ "code": "Unauthorized", "message": "a valid access token is required"}NotFound — the only code this response carries: unknown, or belonging to another merchant. The two are deliberately indistinguishable.
object
Stable machine-readable code — the one thing to branch on. Never parse the message.
English sentence for logs and operators. Wording may change; the code will not.
Example
{ "code": "NotFound", "message": "no such resource"}Nothing to refund NOW: nothing taken or all refunded (NothingToRefund), a refund already in flight (RefundInFlight), more than what remains (RefundExceedsRefundable), or the session has not ended (SessionNotEnded).
object
Stable machine-readable code — the one thing to branch on. Never parse the message.
English sentence for logs and operators. Wording may change; the code will not.
Example
{ "code": "NothingToRefund", "message": "no money was taken on this attempt — or it was all refunded already"}The method cannot: no refund at this PSP (RefundNotSupported), full-only contract (PartialRefundNotSupported), the named operation never took money (NotARefundableOperation) — or the Idempotency-Key already names a refund of a DIFFERENT amount (IdempotencyKeyConflict).
object
Stable machine-readable code — the one thing to branch on. Never parse the message.
English sentence for logs and operators. Wording may change; the code will not.
Example
{ "code": "NotARefundableOperation", "message": "this operation never took money — nothing to refund on it"}