Save a card (token sale)
- 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-saledoesn't read thePayMe-Merchant-Keyheader, so a request without a body MPL returns error1. Partners may sendseller_idwithpayme_client_keyinstead. - Request body field
payme_client_key(optional): Partners only: your partner key (or send thePayMe-Partner-Keyheader). Withseller_payme_id, the seller must belong to you, otherwise error20.
Overview
Saves the buyer's card as a token (buyer_key) for later server-to-server charges. Send sale_type: token to save the card without charging (PayMe sets the price to 100, which is not charged), or capture_buyer: 1 on a normal sale to charge and save. The token arrives as buyer_key in the callback; you can also read it with get-buyer-key.
POST https://sandbox.payme.io/api/generate-sale (production: https://live.payme.io/api/generate-sale), with a JSON body (Content-Type: application/json).
| To | Send |
|---|---|
| Save the card without charging | sale_type: token |
| Charge and save the card | sale_type: sale (default) and capture_buyer: 1 |
| Save a card on a page that can be opened only once | sale_type: token, layout: token-capture and sale_should_be_opened_once: true |
| Charge a saved card later | buyer_key on a new generate-sale; see Create a sale |
To charge and save, send the same request as the example with "sale_type": "sale", your real sale_price and "capture_buyer": 1.
Rules:
- Send
buyer_is_private: trueto tie the token to this seller. Without it the token is account-level: any seller of the same partner can charge it, and aget-buyer-keycall that sendsseller_payme_idfails with error603. - Token capture works with
credit-card,apple-pay,il-direct-debitandmulti; other methods return4. product_nameand a numericsale_priceare required even when nothing is charged.- Store
buyer_keyencrypted: it replaces the card number.
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.
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.
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. |
sale_type |
string | no | token – save the card without charging (the price is set to 100). sale (default) – charge; add capture_buyer: 1 to save the card too. Token capture works with credit-card, apple-pay, il-direct-debit and multi (other methods return 4). The full list is on Sale Types. |
sale_price |
integer | yes | Amount in minor units. Required, but for a token sale any numeric value works: PayMe replaces it with 100 and charges nothing. A missing or non-numeric value returns 352. For a charge-and-save sale, the default allowed range is 500–4000000. |
currency |
string | no | Sale currency, a 3-letter ISO 4217 code. Optional for a token sale (the account's default currency is used); required to charge. |
product_name |
string | yes | Short description shown to the buyer and in the seller's records, up to 500 characters. Required, also for token sales (missing returns 353). |
capture_buyer |
string | no | 1 or true to save the buyer's card as a token after the payment; the token arrives as buyer_key in the callback. Omit it, or send 0, to skip. Works with credit-card, apple-pay, il-direct-debit and multi (other methods return 4). Can't be combined with buyer_key (601). |
buyer_is_private |
boolean | no | With capture_buyer or a token sale: true ties the token to this seller, so get-buyer-key works with the seller's MPL. Without it the token is account-level: any seller of the same partner can charge it, and a get-buyer-key call that sends seller_payme_id fails with error 603. |
buyer_perform_validation |
boolean | no | With capture_buyer or a token sale: whether PayMe validates the card with the issuer before saving the token. Default true. Sending true without capture_buyer or a token sale returns 608. |
sale_payment_method |
string | no | Payment method; see Available Payment Methods. Default credit-card. Send multi to let the buyer choose among every method enabled on the account. Case-insensitive. An unknown value returns 24; a method not enabled on the account returns 720 with the method name; bacs needs GBP and sepa needs EUR (320). Send a string: an array returns 368 (HTTP 400). |
layout |
string | no | Payment page layout: dynamic (default), dynamic-loose (no social ID or CVV validation), qr-sms (Bit: QR code or SMS), token-capture (save a card without a charge; requires sale_type: token). Other values fall back to dynamic. |
sale_should_be_opened_once |
boolean | no | true: with layout: token-capture, the page can be opened only once. Ignored otherwise. |
buyer_key |
string | no | To charge a saved token later, on a new generate-sale: the call charges it at once, with no payment page. Can't be combined with capture_buyer (601) or sale_type: token (602). |
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. |
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. 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. |
sale_return_url |
string | no | Where PayMe redirects the buyer (the iframe or the full page) after a successful payment, with the sale details as query parameters; see Hosted Payment Page options. If omitted, your partner's default return URL is used, if one is set. Same address rules as sale_callback_url (error 21). |
sale_send_notification |
boolean | no | true: PayMe sends the buyer a payment request with the payment link, by email to sale_email and by SMS to sale_mobile. Default false. |
sale_email |
string | no | Buyer's email. Pre-fills the payment page and receives the payment request when sale_send_notification is true. |
sale_mobile |
string | no | Buyer's mobile number. Pre-fills the payment page and receives the SMS payment request when sale_send_notification is true and the SMS service is active on the account. |
sale_name |
string | no | Buyer's full name. Pre-fills the payment page (split at the first space into first and last name) and is used in notifications. |
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. |
Request example
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_type": "token",
"sale_price": 100,
"currency": "ILS",
"product_name": "Save card",
"buyer_is_private": true,
"sale_callback_url": "https://your-server.example.com/payme/callback",
"language": "en"
}
Code samples
curl
curl -X POST 'https://sandbox.payme.io/api/generate-sale' \
-H 'Content-Type: application/json' \
--data-raw '{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_type": "token",
"sale_price": 100,
"currency": "ILS",
"product_name": "Save card",
"buyer_is_private": true,
"sale_callback_url": "https://your-server.example.com/payme/callback",
"language": "en"
}'
Node.js
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",
"sale_type": "token",
"sale_price": 100,
"currency": "ILS",
"product_name": "Save card",
"buyer_is_private": true,
"sale_callback_url": "https://your-server.example.com/payme/callback",
"language": "en"
}),
});
console.log(await response.text());
Python
import requests
response = requests.post(
"https://sandbox.payme.io/api/generate-sale",
json={
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_type": "token",
"sale_price": 100,
"currency": "ILS",
"product_name": "Save card",
"buyer_is_private": True,
"sale_callback_url": "https://your-server.example.com/payme/callback",
"language": "en",
},
)
print(response.text)
PHP
<?php
$body = <<<'BODY'
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_type": "token",
"sale_price": 100,
"currency": "ILS",
"product_name": "Save card",
"buyer_is_private": true,
"sale_callback_url": "https://your-server.example.com/payme/callback",
"language": "en"
}
BODY;
$ch = curl_init('https://sandbox.payme.io/api/generate-sale');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => '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 sale created (success)
| Field | Type | Description |
|---|---|---|
status_code |
integer | 0 success, 1 error. |
sale_url |
string | PayMe's payment page for this sale. Show it to the buyer in an iframe or a redirect, exactly as returned. It stays payable while the sale is initial or failed, until sale_expiry_seconds passes if you sent it. |
payme_sale_id |
string | PayMe's sale ID. Store it: refunds, captures and queries use it. |
payme_sale_code |
integer | Short numeric sale code, for display only. |
price |
integer | Sale amount in minor units (100 for a token sale). |
transaction_id |
string | Your order reference, as sent. |
currency |
string | Sale currency (ISO 4217). |
sale_payment_method |
string | Payment method of the sale, for example credit-card or multi. |
session |
string | Request ID. Quote it when you contact PayMe. |
{
"status_code": 0,
"session": "AtsJ0as5",
"sale_url": "https://sandbox.payme.io/sale/generate/SALE1700-000000AA-EXAMPLE1-SALE0001",
"payme_sale_id": "SALE1700-000000AA-EXAMPLE1-SALE0001",
"payme_sale_code": 12345678,
"price": 100,
"transaction_id": null,
"currency": "ILS",
"sale_payment_method": "credit-card"
}
500 — Request refused. Most request errors return HTTP 500 with status_code: 1; some return 400, 403, 422 or 429. See 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. |
{
"status_code": 1,
"status_error_details": "Seller was not found",
"status_additional_info": "seller_payme_id",
"status_error_code": 251,
"session": "AtsJ0as5"
}