# Charge a Hosted Fields token Building with an AI agent? Start at https://docs.payme.io/agents.md - Sandbox: `POST https://sandbox.payme.io/api/generate-sale` - Production: `POST https://live.payme.io/api/generate-sale` ## Credentials - Request body field `seller_payme_id` (required): The seller's MPL. Send it in the JSON body: `generate-sale` doesn't read the `PayMe-Merchant-Key` header, so a request without a body MPL returns error `1`. Partners may send `seller_id` with `payme_client_key` instead. - Request body field `payme_client_key` (optional): Partners only: your partner key (or send the `PayMe-Partner-Key` header). With `seller_payme_id`, the seller must belong to you, otherwise error `20`. ## Overview Charges the token that `instance.tokenize()` returned, from your server, in one call: send it as `buyer_key`. There is no payment page and no `sale_url`. Read the result from `status_code`: a declined charge also returns HTTP 200. `POST https://sandbox.payme.io/api/generate-sale` (production: `https://live.payme.io/api/generate-sale`), with a JSON body (`Content-Type: application/json`). This is the server step of the [Hosted Fields guide](/accepting-payments/checkout-and-in-person/hosted-fields-jsapi-guide). The same call charges any saved token; see [Save a card and charge it later](/accepting-payments/capture-and-saved-cards/save-a-card-and-charge-it-later). | To | Send | |---|---| | Charge now (J4) | `sale_type: sale` (default) | | Authorize now, capture later (J5, up to 168 hours) | `sale_type: authorize`; then [capture-sale](/accepting-payments/capture-and-saved-cards/capture-sale) | ### Credentials Send `seller_payme_id` (the MPL) in the JSON body: this endpoint doesn't read the `PayMe-Merchant-Key` header, so a request without a body MPL returns error `1`. Partners add `payme_client_key` (or the `PayMe-Partner-Key` header) and may name the seller by `seller_id` instead. See [Authentication](/payments/getting-started/authentication). ### What to expect - Success: `status_code: 0` and the sale and transaction fields, the same as the callback. - Decline: **HTTP 200** with `status_code: 1`, `status_error_code` (for example `20004`) and `status_error_details`. - Every call creates a new sale, even when the charge is refused. Check the sale before you retry; see [Idempotency and Retries](/payments/getting-started/idempotency-and-retries). - The token's own payment method is used. - Errors: `buyer_key` with `capture_buyer` returns `601`, with `sale_type` `token`/`seller-token` `602`, with `template` `606`, and with `multi-capture` `357`. A token of another seller returns `605`; an inactive or already-used single-use token returns `604`; a charge over the seller's processing limit returns `130`. - Never put card numbers in any field (error `20`), and don't send the legacy `price` field (major units; it overrides `sale_price`). ### Callbacks When the sale is paid, PayMe sends a `POST` with an `application/x-www-form-urlencoded` body to `sale_callback_url`. The notification types and fields are on [Callbacks](/payments/getting-started/callbacks). ### Issuing an invoice to a business With the invoicing service active on the account, send `buyer_business_name` and `buyer_business_code` to issue the invoice to a business. Send both, or neither. ## Parameters This endpoint takes no path, query or header parameters. ## Request body Content type: `application/json` | Field | Type | Required | Description | | --- | --- | --- | --- | | `seller_payme_id` | string | yes | The seller's MPL. Send it in the JSON body: `generate-sale` doesn't read the `PayMe-Merchant-Key` header, so a request without a body MPL returns error `1`. Partners may send `seller_id` with `payme_client_key` instead. | | `payme_client_key` | string | no | Partners only: your partner key (or send the `PayMe-Partner-Key` header). With `seller_payme_id`, the seller must belong to you, otherwise error `20`. | | `seller_id` | string | no | Partners only: your own ID for the seller, set in `create-seller`, sent instead of `seller_payme_id`. Requires `payme_client_key`. | | `buyer_key` | string | yes | The token from `instance.tokenize()`, or a saved `buyer_key`. The sale is charged at once. | | `sale_price` | integer | yes | Sale amount in minor units: 50.75 is sent as `5075`. The default allowed range is `500`–`4000000`, the same in every currency; PayMe can set a different range for a partner. A missing, non-numeric or out-of-range value returns error `352`. Decimals are rounded. | | `currency` | string | yes | Sale currency, a 3-letter [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) code such as `ILS`, enabled on the account (otherwise error `252`). Required for `sale` and `authorize`; a `token` or `template` sale without it uses the account's default currency. | | `product_name` | string | yes | Short description of the product or service, up to 500 characters. Shown to the buyer, and on the invoice when the invoicing service is active. Missing returns error `353`. | | `transaction_id` | string | no | Your own order reference, up to 50 characters. PayMe returns it in responses and callbacks but doesn't check it for uniqueness. | | `installments` | string | no | Number of payments: `1` (default) to `12`. More than one installment is ILS only (`312`) and needs a card token. Fixed values above 12 fail unless PayMe has enabled more installments on your account. A non-numeric value returns `10`, an ILS price lower than the number of installments `358`. | | `sale_type` | string | no | `sale` (default) – charge now (J4). `authorize` – reserve the amount for up to 168 hours, then capture it with [`capture-sale`](/accepting-payments/capture-and-saved-cards/capture-sale) (J5). `token`, `seller-token` and `template` can't be combined with `buyer_key` (`602`, `606`). | | `market_fee` | number | no | The partner's (marketplace's) fee: a percentage of the sale price, VAT included, from `0` to `60`. It is added on top of PayMe's fees and transferred to the marketplace once a month. Default: the seller's market fee set at `create-seller`. A non-numeric value returns `10`, a negative one `304`, and more than 60 `308`. Ignored for sellers paid directly. | | `sale_callback_url` | string | no | Where PayMe sends server-to-server callbacks for this sale, as a form-encoded `POST`; see [Callbacks](/payments/getting-started/callbacks). If omitted, PayMe uses your partner's default callback URL, if one is set; a seller has no dashboard setting for it, so send it on every call. Must be a public address: `localhost`, private or loopback IP addresses and IPv6 addresses are refused with error `21`, which fails the whole call. | | `language` | string | no | Language of the payment page and the error messages. Default `he`. `he` and `en` are fully supported; `es`, `ru` and `ar` are accepted, but messages and the payment page are then mostly in English. Case-insensitive; any other value, or an empty string, returns error `51`. | | `buyer_business_name` | string | no | With the invoicing service: the business name the invoice is issued to. Send it together with `buyer_business_code`, or neither. | | `buyer_business_code` | integer | no | With the invoicing service: the business code (VAT identifier) the invoice is issued to. Send it together with `buyer_business_name`, or neither. | | `items` | array | no | Line items of the sale, as an array of objects. If you send `items`, every item needs `name`, `quantity`, `unit_price` and `total`; an invalid item returns error `20` (HTTP 422) with the failing rules in `status_additional_info`. Item keys are case-insensitive. | | `items[].name` | string | yes | Item name, 1–50 characters. | | `items[].quantity` | integer | yes | Quantity, `0`–`999999`. | | `items[].unit_price` | integer | yes | Price of one unit, in minor units. | | `items[].total` | integer | yes | Line total after discount, in minor units, `0`–`9000000000`. | | `items[].unit_measurement` | string | no | Unit of measurement, for example `kg`. | | `items[].discount_total` | number | no | Discount on this line, in minor units, sent as a negative number. | | `items[].description` | string | no | Item description, up to 150 characters. | | `items[].product_code` | string | no | Your catalog code for the item, up to 100 characters. | | `items[].commodity_code` | number | no | Numeric commodity code of the item. | | `items[].custom1` | string | no | Free text for your own use, up to 100 characters. | | `items[].custom2` | string | no | Free text for your own use, up to 100 characters. | ### Request example ```json { "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "buyer_key": "BUYERDEMO-BUYERDEMO-BUYERDEMO-1234567", "sale_price": 1000, "currency": "ILS", "product_name": "Smartphone", "transaction_id": "order-1001", "installments": "1", "sale_callback_url": "https://your-server.example.com/payme/callback", "language": "en" } ``` ## Code samples ### curl ```bash curl -X POST 'https://sandbox.payme.io/api/generate-sale' \ -H 'Content-Type: application/json' \ --data-raw '{ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "buyer_key": "BUYERDEMO-BUYERDEMO-BUYERDEMO-1234567", "sale_price": 1000, "currency": "ILS", "product_name": "Smartphone", "transaction_id": "order-1001", "installments": "1", "sale_callback_url": "https://your-server.example.com/payme/callback", "language": "en" }' ``` ### Node.js ```javascript const response = await fetch("https://sandbox.payme.io/api/generate-sale", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "buyer_key": "BUYERDEMO-BUYERDEMO-BUYERDEMO-1234567", "sale_price": 1000, "currency": "ILS", "product_name": "Smartphone", "transaction_id": "order-1001", "installments": "1", "sale_callback_url": "https://your-server.example.com/payme/callback", "language": "en" }), }); console.log(await response.text()); ``` ### Python ```python import requests response = requests.post( "https://sandbox.payme.io/api/generate-sale", json={ "seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567", "buyer_key": "BUYERDEMO-BUYERDEMO-BUYERDEMO-1234567", "sale_price": 1000, "currency": "ILS", "product_name": "Smartphone", "transaction_id": "order-1001", "installments": "1", "sale_callback_url": "https://your-server.example.com/payme/callback", "language": "en", }, ) print(response.text) ``` ### PHP ```php 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => $body, ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ## Responses ### 200 — Token charged. The response holds the sale and transaction fields, the same as the callback, and has no `sale_url`. (success) | Field | Type | Description | | --- | --- | --- | | `status_code` | integer | `0` the token was charged; `1` the charge failed (a decline also comes with HTTP 200). | | `payme_status` | string | `success` or `error`. | | `status_error_code` | integer | `0` on success; otherwise the error or decline code, see [Errors](/payments/getting-started/errors). | | `payme_sale_id` | string | PayMe's sale ID. Every call creates a new sale, even when the charge is refused. | | `payme_sale_code` | integer | Short numeric sale code, for display only. | | `sale_status` | string | See [Sale Statuses](/payments/codes-statuses/sale-statuses): `completed` for a charge, `authorized` for `sale_type: authorize`. | | `sale_type` | string | Sale type name, for example `Sale`; see [Sale Types](/payments/codes-statuses/sale-types). | | `sale_payment_method` | string | The token's payment method; it replaces any `sale_payment_method` you sent. | | `price` | integer | Sale amount in minor units. | | `currency` | string | Sale currency (ISO 4217). | | `transaction_id` | string | Your order reference, as sent. | | `is_token_sale` | boolean | `false`: this charge isn't a token-saving sale. | | `payme_signature` | string | Signature, computed as described on [Callbacks](/payments/getting-started/callbacks). | | `payme_transaction_id` | string | PayMe's ID for this charge. | | `payme_transaction_total` | integer | Amount of this transaction, in minor units. | | `payme_transaction_auth_number` | string | Authorization number from the card company. | | `buyer_card_mask` | string | First 6 and last 4 digits of the card. | | `installments` | integer | Number of installments. | | `sale_paid_date` | string | When the payment happened. | | `sale_3ds` | boolean | Whether 3D Secure was used. | ```json { "status_code": 0, "payme_status": "success", "status_error_code": 0, "payme_sale_id": "SALE1700-000000AA-EXAMPLE1-SALE0001", "payme_sale_code": 12345678, "sale_status": "completed", "sale_type": "Sale", "sale_payment_method": "credit-card", "price": 1000, "currency": "ILS", "transaction_id": "order-1001", "is_token_sale": false, "payme_signature": "f8ffc5bb45fe6c3ad326c439f1a21c28", "payme_transaction_id": "TRAN1700-000000AA-EXAMPLE1-TXN00001", "payme_transaction_total": 1000, "payme_transaction_auth_number": "0123456", "buyer_card_mask": "455743******3431", "installments": 1, "sale_paid_date": "2026-11-09 10:15:02", "sale_3ds": false } ``` ### 200 — Declined. A declined token charge returns HTTP 200; check `status_code`. (error) | Field | Type | Description | | --- | --- | --- | | `status_code` | integer | `1`: the charge failed. | | `status_error_code` | integer | Decline or error code, for example `20004`; see [Errors](/payments/getting-started/errors). | | `status_error_details` | string | The message, in the requested `language`. | | `payme_sale_id` | string | The sale this call created. | ```json { "status_code": 1, "status_error_code": 20004, "status_error_details": "Refusal by credit company. Please try a different card", "payme_sale_id": "SALE1700-000000AA-EXAMPLE1-SALE0001", "sale_url": "https://sandbox.payme.io/sale/generate/SALE1700-000000AA-EXAMPLE1-SALE0001" } ``` ### 500 — Request refused. Most request errors return HTTP 500 with `status_code: 1`; some return 400, 403, 422 or 429. See [Errors](/payments/getting-started/errors). (error) | Field | Type | Description | | --- | --- | --- | | `status_code` | integer | `1` for an error. | | `status_error_code` | integer | PayMe's error code, for example `251` (seller not found) or `352` (invalid price). | | `status_error_details` | string | The error message, in the requested `language` (Hebrew by default). | | `status_additional_info` | string | Extra detail, usually the name of the field at fault. | | `session` | string | Request ID. Quote it when you contact PayMe. | ```json { "status_code": 1, "status_error_details": "Seller was not found", "status_additional_info": "seller_payme_id", "status_error_code": 251, "session": "AtsJ0as5" } ```