# Refund a POS sale Building with an AI agent? Start at https://docs.payme.io/agents.md - Sandbox: `PUT https://sandbox.payme.io/api/sales/{sale_guid}` - Production: `PUT https://live.payme.io/api/sales/{sale_guid}` ## Credentials - Request body field `seller_payme_id` (required): The seller's MPL. The sale must belong to this seller. - Request body field `payme_client_key` (optional): Partners only: your partner key. You can send it in the `PayMe-Partner-Key` header instead. ## Overview Refunds a sale paid on a POS device. PayMe sends the refund to the device in `payment.pos_id` and returns the result in the same response. Example: `PUT https://sandbox.payme.io/api/sales/SALE1700-000000AA-EXAMPLE1-SALE0001`. - Send `payment.action` `refund`. Without it, this endpoint pays the sale instead of refunding it (see [POS module overview](/payments/point-of-sale-pos)). - Leave out `payment.amount` to refund everything that can still be refunded, or send a smaller amount for a partial refund. - `payment.verify_only` `true` runs the checks and returns without refunding. - `refunded_from_creditcard` is `true` when the seller's balance didn't cover the refund and PayMe charged the seller's card on file for the difference. ## Authentication Send `seller_payme_id` (the seller's MPL) in the JSON body. The sale must belong to this seller. Partners also send `payme_client_key`, in the body or the `PayMe-Partner-Key` header. ## Errors | HTTP | Code | When | |---|---|---| | 500 | `1` | A required field is missing: `seller_payme_id`, `payment` or `payment.method`. | | 500 | `350` | No sale has this ID. | | 500 | `4` | `payment.method` isn't the sale's payment method (`pos`). | | 400 | `720` | The POS service isn't active for this seller. | | 400 | `26014` | `payment.pos_id` is missing, or the seller has no device with this ID. | | 400 | `26017` | The device has no POS record. | | 400 | `26018` | The device isn't active. | | 500 | Decline code | The device or the card company declined the refund. | ## Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `sale_guid` | path | string | yes | The sale's `payme_sale_id`. | ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `seller_payme_id` | string | yes | The seller's MPL. The sale must belong to this seller. | | `payme_client_key` | string | no | Partners only: your partner key. You can send it in the `PayMe-Partner-Key` header instead. | | `payment` | object | yes | The refund to send to the device. | | `payment.method` | string | yes | `pos`. It must match the sale's payment method. | | `payment.action` | string | yes | `refund`. Without it, the call pays the sale instead of refunding it. | | `payment.pos_id` | string | yes | The device that processes the refund. | | `payment.amount` | integer | no | Amount to refund, in minor units. Default: everything that can still be refunded. | | `payment.verify_only` | boolean | no | `true` runs the checks without refunding. | | `language` | string | no | Language of messages: `he` (default), `en`, `es`, `ru` or `ar`. | ### Request example ```json { "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "payment": { "method": "pos", "action": "refund", "pos_id": "001" }, "language": "en" } ``` ## Code samples ### curl ```bash curl -X PUT 'https://sandbox.payme.io/api/sales/' \ -H 'Content-Type: application/json' \ --data-raw '{ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "payment": { "method": "pos", "action": "refund", "pos_id": "001" }, "language": "en" }' ``` ### Node.js ```javascript const response = await fetch("https://sandbox.payme.io/api/sales/", { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "payment": { "method": "pos", "action": "refund", "pos_id": "001" }, "language": "en" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.put( "https://sandbox.payme.io/api/sales/", json={ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "payment": { "method": "pos", "action": "refund", "pos_id": "001", }, "language": "en", }, ) print(response.text) ``` ### PHP ```php '); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — The refund was processed. (success) | Field | Type | Description | | --- | --- | --- | | `status_code` | integer | `0` on success. | | `payme_status` | string | `success`. | | `payme_sale_id` | string | PayMe's sale ID. | | `payme_sale_code` | integer | PayMe's numeric sale ID. | | `payme_sale_status` | string | `refunded`, or `partial-refund` after a partial refund. | | `sale_status` | string | Same as `payme_sale_status`. | | `currency` | string | ISO 4217 currency code. | | `price` | integer | The original sale amount, in minor units. | | `transaction_id` | string | Your reference for the sale. | | `sale_refund_buffer` | integer | Amount that can still be refunded, in minor units. | | `payme_transaction_id` | string | ID of the refund transaction. | | `payme_transaction_total` | integer | Amount refunded, in minor units. | | `payme_transaction_card_brand` | string | Card brand. | | `payme_transaction_auth_number` | string | Authorization number of the refund. | | `payme_signature` | string | Signature of the refund. See [Callbacks](/payments/getting-started/callbacks). | | `refunded_from_creditcard` | boolean | `true` if PayMe charged the seller's card on file because the balance didn't cover the refund. | | `sale_invoice_number` | string | Number of the credit document, if the invoicing service issued one. Otherwise `null`. | | `sale_invoice_url` | string | Link to the credit document, if one was issued. Otherwise `null`. | ```json { "status_code": 0, "payme_status": "success", "payme_sale_id": "SALE1700-000000AA-EXAMPLE1-SALE0001", "payme_sale_code": 12346578, "payme_sale_status": "refunded", "sale_status": "refunded", "currency": "ILS", "price": 10000, "transaction_id": "order-1001", "sale_refund_buffer": 0, "payme_transaction_id": "TRAN1700-000000AA-EXAMPLE1-TRAN0002", "payme_transaction_total": 10000, "payme_transaction_card_brand": "Mastercard", "payme_transaction_auth_number": "0123456", "payme_signature": "db1c276**********c5b39", "refunded_from_creditcard": false, "sale_invoice_number": null, "sale_invoice_url": null } ``` ### 400 — The device or the POS service can't take the refund. See the error table. (error) | Field | Type | Description | | --- | --- | --- | | `status_code` | integer | `1` on failure. | | `status_error_details` | string | What went wrong, in the language you asked for (Hebrew by default). | | `status_additional_info` | string | The field or value concerned. Can be `null`. | | `status_error_code` | integer | PayMe error code. See the error table above and [Errors](/payments/getting-started/errors). | | `session` | string | PayMe session ID. Quote it when you contact support. | ```json { "status_code": 1, "status_error_details": "Desired device is inactive", "status_additional_info": null, "status_error_code": 26018, "session": "FhT3aXe7" } ``` ### 500 — The request was refused or the refund was declined. See the error table. (error) | Field | Type | Description | | --- | --- | --- | | `status_code` | integer | `1` on failure. | | `status_error_details` | string | What went wrong, in the language you asked for (Hebrew by default). | | `status_additional_info` | string | The field or value concerned. Can be `null`. | | `status_error_code` | integer | PayMe error code. See the error table above and [Errors](/payments/getting-started/errors). | | `session` | string | PayMe session ID. Quote it when you contact support. | ```json { "status_code": 1, "status_error_details": "Sale was not found", "status_additional_info": "SALE1700-000000AA-EXAMPLE1-SALE0001", "status_error_code": 350, "session": "FhT3aXe7" } ```