# Take in-person payments with a POS device Building with an AI agent? Start at https://docs.payme.io/agents.md ## Prerequisites - Partner credentials (payme_client_key) from PayMe Partners, for ordering and pairing devices - The seller's seller_payme_id (MPL) - The POS service active on the seller's account - A callback URL on your partner account, for the pairing callbacks ## Related - [Point of Sale (POS)](/payments/point-of-sale-pos) - [Order POS devices](/payments/point-of-sale-pos/post-vas-enable) - [Create a POS payment](/payments/point-of-sale-pos/post-payment) - [Refund a POS sale](/payments/point-of-sale-pos/put-sales) - [Callback types reference](/payments/getting-started/callback-types) - [Enable payment methods and services for your sellers](/marketplaces-and-platforms/seller-onboarding/enable-services) - [Understand the sale lifecycle](/payments/codes-statuses/sale-lifecycle) - [Errors](/payments/getting-started/errors) - [List sales](/payments/query-apis/post-get-sales) A PayMe POS device takes card-present payments for a seller. Your system sends each payment to the device through the Payments API, the buyer pays on the device, and the result comes back in the same response. This guide covers the whole flow: ordering devices, pairing them, taking and refunding payments, and transmitting the day's transactions. Endpoint details are in the [POS module overview](/payments/point-of-sale-pos) and its endpoint pages. ## How it works 1. **Order the devices.** A partner orders devices for its seller with `vas-enable`. PayMe prepares the devices, pairs them and ships them. 2. **Pair and authenticate.** A device takes payments only after it is paired and then authenticated. PayMe does both for new devices. You can also do it yourself with `pos/pair` and `pos/authenticate`. Each step sends you a callback. 3. **Take a payment.** Call `POST /sales` with `payment.method: pos` and the device's `pos_id`. PayMe pushes the payment to the device and waits for the buyer. 4. **Refund on the device.** Call `PUT /sales/{payme_sale_id}` with `payment.action: refund`. 5. **Transmit.** `pos/transmit` sends the device's transactions for deposit and returns the transmission report. ## Before you start | You need | For | |---|---| | Your partner key (`payme_client_key`) | Ordering devices, and the `pos/pair`, `pos/authenticate` and `pos/transmit` calls. These calls are for partners only. | | The seller's `seller_payme_id` (MPL) | Every call. On its own, it authenticates payments and refunds. | | The POS service active on the seller's account | Without it, POS calls return error `720`. | | A callback URL on your partner account | The `point-of-sale-action-*` callbacks. If your partner account has none, they aren't sent. | Base URLs: `https://sandbox.payme.io/api` (sandbox) and `https://live.payme.io/api` (production). Send JSON with `Content-Type: application/json`. On the `pos/*` calls, every field goes in the JSON body, including `payme_client_key`. ## Step 1: Order the devices Order devices for the seller with [Order POS devices](/payments/point-of-sale-pos/post-vas-enable): one `vas-enable` call turns on the POS payment method, and a second one sends the device list in `vas_data`. The general `vas-enable` flow, including how to check the result, is in [Enable payment methods and services for your sellers](/marketplaces-and-platforms/seller-onboarding/enable-services). - **Adding devices later.** Send only the new devices, with `vas_data.extend_items: true`. Without it, the list you send replaces the devices already ordered. - **It takes time.** The order is handled by hand: PayMe requests a new terminal, which can take up to 5 business days, then prepares, pairs and ships the devices. - **Keep each `pos_id`.** It names the device in every later call. Send it exactly as it appears in the order and in the pair callback. ## Step 2: Pair and authenticate a device A device can take payments only after two steps: `pos/pair` registers the device for the seller, and `pos/authenticate` completes the pairing with a 6-digit verification code. PayMe runs both steps for new devices before they ship, and you receive the two callbacks. To pair a device from your own system, use the calls below. ### Pair ```bash curl -X POST https://sandbox.payme.io/api/pos/pair \ -H 'Content-Type: application/json' \ -d '{ "payme_client_key": "payme_partner_key", "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "pos_id": "001", "terminal_id": "YOUR_TERMINAL_ID", "name": "Front counter" }' ``` | Field | Required | Description | |---|---|---| | `payme_client_key` | Yes | Your partner key. | | `seller_payme_id` | Yes | The seller's MPL. | | `pos_id` | Yes | The device's ID from the seller's device order. A device that isn't in the order returns `26014`. | | `terminal_id` | Yes | The device's payment terminal ID. | | `name` | No | A name for the device. Default: the seller's business name. The callbacks return it as `pos_name`. | On success, the response is `status_code` `0`, PayMe records the device as paired but not yet active, and it sends `point-of-sale-action-pair-update`. ```json { "status_code": 0, "session": "FhT3aXe7" } ``` Pairing a device again starts over: the device stops taking payments until you authenticate it again. ### Authenticate ```bash curl -X POST https://sandbox.payme.io/api/pos/authenticate \ -H 'Content-Type: application/json' \ -d '{ "payme_client_key": "payme_partner_key", "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "pos_id": "001", "terminal_id": "YOUR_TERMINAL_ID", "verification_code": "482913" }' ``` `verification_code` is the 6-digit verification code for this pairing. Send it as a string, so that a leading zero is kept. A code that isn't a number returns error `10`, and one that isn't exactly 6 digits returns `999`. Authenticating a device that was never paired returns `26017`. On success, the response is `status_code` `0`, the device becomes active, and PayMe sends `point-of-sale-action-authenticate-update`. The device can now take payments. If you don't have a device's terminal ID or its verification code, ask PayMe Partners (). ### The pairing callbacks PayMe sends both callbacks to your partner callback URL. They carry the seller fields of the seller callbacks, plus: | `notify_type` | When | Device fields | |---|---|---| | `point-of-sale-action-pair-update` | `pos/pair` succeeded | `pos_id`, `pos_name` | | `point-of-sale-action-authenticate-update` | `pos/authenticate` succeeded, and the device is active | `pos_id`, `pos_name` | They aren't signed. The seller fields and the delivery rules are on [Callback types](/payments/getting-started/callback-types#sellers). ### When the device service refuses `pos/pair`, `pos/authenticate` and `pos/transmit` pass your request to the service that runs the devices. If that service refuses the request or can't be reached, the call returns **HTTP 200** with `status_code` `1`, `status_error_code` `20002`, and the service's message in `status_error_details`: ```json { "status_code": 1, "session": "FhT3aXe7", "status_error_code": 20002, "status_error_details": "Message from the device service" } ``` Always check `status_code`, not the HTTP status. A refused call changes nothing for the device and sends no callback. ## Step 3: Take a payment Send the payment to the device with [Create a POS payment](/payments/point-of-sale-pos/post-payment): ```bash curl -X POST https://sandbox.payme.io/api/sales \ -H 'Content-Type: application/json' \ -d '{ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "sale_price": 10000, "currency": "ILS", "product_name": "Coffee beans 1kg", "transaction_id": "order-1001", "sale_callback_url": "https://your-server.example.com/payme/callback", "payment": { "method": "pos", "pos_id": "001" }, "language": "en" }' ``` `currency` is required, and `sale_price` is in minor units (`10000` = 100.00). PayMe pushes the payment to the device and waits while the buyer pays, so the call stays open until the device answers. Give your HTTP client a long timeout. A paid sale returns, shortened: ```json { "status_code": 0, "payme_status": "success", "status_error_code": 0, "payme_sale_id": "SALE1700-000000AA-EXAMPLE1-SALE0001", "payme_sale_code": 12346578, "payme_sale_status": "completed", "sale_status": "completed", "currency": "ILS", "transaction_id": "order-1001", "price": 10000, "payme_transaction_id": "TRAN1688-034834SZ-OYNALKNE-DWOXFEUZ", "payme_transaction_auth_number": "12345678", "installments": 1 } ``` Keep `payme_sale_id`: you need it to refund. | Outcome | Response | What to do | |---|---|---| | Paid | HTTP 200, `status_code` `0`, `payme_sale_status` `completed` | Done. | | Declined or canceled on the device | HTTP 200, `status_code` `1`, with `status_error_code` and `status_error_details` | Show the reason. To try again, send a new payment. | | The device didn't answer in time | HTTP 400, `status_error_code` `26020` ("The payment is being verified") | Don't send the payment again. PayMe keeps checking it for up to 5 minutes, then completes or fails the sale. Wait for the sale callback, or read the sale with [`get-sales`](/payments/query-apis/post-get-sales). | | The device can't take payments | HTTP 400 with `720`, `26014`, `26017` or `26018` | See [Errors](#errors). | A paid sale sends `sale-complete` and a failed one sends `sale-failure`, to `sale_callback_url`. See [Callback types](/payments/getting-started/callback-types#sales). More options: - `sale_type: authorize` only authorizes the card. `installments` and the other [`generate-sale`](/payments/hosted-payment-page/post-generate-sale) sale fields work here too. - You can also create the sale first with `generate-sale` and `sale_payment_method: pos`, then push it to the device with `PUT /sales/{payme_sale_id}`. The [POS module overview](/payments/point-of-sale-pos) shows this two-step flow. - Which payment methods a device accepts depends on the device. Ask PayMe Partners () for the current list. ### What the buyer sees on the device 1. The payment is sent to the device. ![image.png](/marketplaces-and-platforms/_files/wql9AovEPpE.png) ![image.png](/marketplaces-and-platforms/_files/UX8FGAfVcFo.png) 2. The buyer pays. ![image.png](/marketplaces-and-platforms/_files/q4trw0Af1bw.png) 3. Pending approval from the card company. ![image.png](/marketplaces-and-platforms/_files/ZRLRGnlC0cE.png) 4. Payment confirmed. ![image.png](/marketplaces-and-platforms/_files/dnyClwzqPbY.png) 5. Payment deposited. ![image.png](/marketplaces-and-platforms/_files/GvNGRyvai2g.png) 6. Final confirmation. ![image.png](/marketplaces-and-platforms/_files/TusLBf0j87k.png) ## Step 4: Refund on the device Refund with [Refund a POS sale](/payments/point-of-sale-pos/put-sales). The refund runs on the device in `payment.pos_id`: ```bash curl -X PUT https://sandbox.payme.io/api/sales/SALE1700-000000AA-EXAMPLE1-SALE0001 \ -H 'Content-Type: application/json' \ -d '{ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "payment": { "method": "pos", "action": "refund", "pos_id": "001" }, "language": "en" }' ``` - **Always send `payment.action: refund`.** Without it, this call pays the sale instead of refunding it. - Leave out `payment.amount` to refund everything that can still be refunded, or send a smaller amount, in minor units, for a partial refund. - The result comes back in the same response: `payme_sale_status` is `refunded`, or `partial-refund`. PayMe also sends a `refund` callback. ## Step 5: Transmit the day's transactions The device's transactions are deposited when they are transmitted. `pos/transmit` runs this transmission now, for example at the end of the business day, and returns its report. Ask PayMe Partners whether the seller's devices also transmit on their own. ```bash curl -X POST https://sandbox.payme.io/api/pos/transmit \ -H 'Content-Type: application/json' \ -d '{ "payme_client_key": "payme_partner_key", "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "pos_id": "001", "terminal_id": "YOUR_TERMINAL_ID" }' ``` ```json { "status_code": 0, "session": "FhT3aXe7", "acknowledge_number": "000123", "report": "Transmission report text" } ``` | Field | Type | Description | |---|---|---| | `acknowledge_number` | string | The acknowledgment number of the transmission. Empty if the device service returned none. | | `report` | string | The transmission report (Z report), as text from the device service. Empty if it returned none. | Call it only for a paired device. A refused transmission returns `status_code` `1` with `20002`, as in [Step 2](#when-the-device-service-refuses). ## Errors | Code | HTTP | Calls | Meaning | What to do | |---|---|---|---|---| | `1` | 500 | All | A required field is missing. `status_additional_info` names it. | Add the field. | | `720` | 400 | All | The POS service isn't active for the seller. | Order the devices ([Step 1](#step-1-order-the-devices)). | | `26014` | 400 | All | `pos_id` is missing, or no device in the seller's order has it. | Send the `pos_id` from the order. | | `26017` | 400 | Authenticate, payment, refund | The device hasn't been paired. | Pair it. | | `26018` | 400 | Payment, refund | The device is paired but not authenticated, for example after it was paired again. | Authenticate it. | | `26020` | 400 | Payment | The device didn't answer in time. PayMe is still checking the payment. | Wait for the sale callback. Don't send the payment again. | | `20002` | 200, `status_code` `1` | Pair, authenticate, transmit | The device service refused the request or couldn't be reached. | Check the IDs and the code, then try again. | | `10` | 500 | Authenticate | `verification_code` isn't a number. | Send 6 digits. | | `999` | 500 | Authenticate | `verification_code` isn't exactly 6 digits. | Send 6 digits, as a string. | | A decline code | 200, `status_code` `1` | Payment | The payment was declined or canceled on the device. | Show the reason; send a new payment to try again. | Credential errors, such as `200` (unknown partner key) and `251` (unknown seller key), are on [Errors](/payments/getting-started/errors). ## Related - [POS module overview](/payments/point-of-sale-pos) - [Order POS devices](/payments/point-of-sale-pos/post-vas-enable), [Create a POS payment](/payments/point-of-sale-pos/post-payment), [Refund a POS sale](/payments/point-of-sale-pos/put-sales) - [Callback types](/payments/getting-started/callback-types) - [Understand the sale lifecycle](/payments/codes-statuses/sale-lifecycle)