Save a card and charge it later
Prerequisites
- Seller's seller_payme_id (MPL), kept on your server
- A public HTTPS URL for callbacks (not localhost or a private IP)
Related
- Save a card (token sale)
- Save a card as a token
- Get the buyer key of a sale or subscription
- Create a sale (hosted payment page)
- Hosted Fields JSAPI guide
- Build recurring billing with subscriptions
- Test Cards and Payment Methods
Save a buyer's card once as a token, the buyer_key, and charge it from your server whenever you need to: a repeat order, a top-up, or a charge after delivery. The buyer doesn't have to be present, and the card number never reaches your servers.
This guide covers the ways to save a card, the two settings that decide what a token can do, how to charge it, and how to keep tokens safe. To charge a saved card on a fixed schedule, see Build recurring billing with subscriptions.
Before you start
- Credentials. The seller's
seller_payme_id(MPL), in the JSON body. Partners also sendpayme_client_key. Keep both on your server: together with abuyer_key, the MPL is all it takes to charge the card. See Authentication. - Base URL.
https://sandbox.payme.io/api/in the sandbox,https://live.payme.io/api/in production. A token works only in the environment where it was saved. - A callback URL. A public address for
sale_callback_url.localhostand private IP addresses are refused with error21. See Callbacks.
1. Save the card
| Way | Charges the buyer? | Who handles the card | Use it when |
|---|---|---|---|
capture_buyer: 1 on generate-sale |
Yes, the sale amount | PayMe's payment page (sale_url) |
The first order should also save the card. |
sale_type: token on generate-sale |
No | PayMe's payment page (sale_url) |
You want a card on file before any charge, for example at sign-up. |
Hosted Fields tokenize() |
No | PayMe's card fields inside your own checkout | Your checkout must look native to your site. |
capture-buyer-token |
No | Your server sends the card number | You are PCI DSS Level 1 certified. |
Saving works with the payment methods credit-card, apple-pay, il-direct-debit and multi. Other methods return error 4.
Save while charging (capture_buyer)
Add capture_buyer: 1 to a regular generate-sale and show the buyer the sale_url. When the buyer pays, PayMe charges the card, saves it, and sends the buyer_key in the sale-complete callback.
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_price": 5000,
"currency": "ILS",
"product_name": "First order",
"transaction_id": "order-1001",
"capture_buyer": 1,
"buyer_is_private": true,
"sale_callback_url": "https://your-server.example.com/payme/callback",
"language": "en"
}
Save without charging (sale_type: token)
Send sale_type: token on generate-sale and show the buyer the sale_url. Nothing is charged: PayMe sets the price to 100 and doesn't charge it, but product_name and a numeric sale_price are still required. The buyer_key arrives in the sale-complete callback. For a page that can be opened only once, add layout: token-capture and sale_should_be_opened_once: true.
{
"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"
}
Save in your own checkout (Hosted Fields)
In the browser, instance.tokenize() returns a token: that is the buyer_key. Send it to your server and charge it there. A Hosted Fields token is permanent unless you create the instance with tokenIsPermanent: false, and account-level unless you pass buyerIsPrivate: true (both explained below). Setup and code: Hosted Fields JSAPI guide.
Save from your server (capture-buyer-token)
capture-buyer-token takes the card number, expiry and CVV, so use it only if you are PCI DSS Level 1 certified. It returns the buyer_key in the response. The token is single-use unless you send buyer_is_permanent: true.
2. Decide what the token can do
Two settings, sent when you save the card, decide how often the token can be charged and who can charge it.
Single-use or permanent
| Saved with | Default |
|---|---|
capture_buyer or sale_type: token |
Permanent. |
| Hosted Fields | Permanent. tokenIsPermanent: false makes it single-use. |
capture-buyer-token |
Single-use. buyer_is_permanent: true makes it permanent. |
A permanent token can be charged any number of times and doesn't expire in PayMe. A single-use token is deactivated by the first charge, even when that charge is declined. Later charges return error 604 ("Buyer inactive"), and a subscription refuses it with error 376. Save permanent tokens unless you want exactly one charge.
Seller-level or account-level (buyer_is_private)
buyer_is_private: true (seller-level) |
Not sent (account-level, the default) | |
|---|---|---|
| Who can charge it | Only the seller (MPL) that saved it | Any seller of the same partner |
Read it back with get-buyer-key |
seller_payme_id, or a partner's payme_client_key |
payme_client_key only. Sending seller_payme_id returns error 603. |
In Hosted Fields the option is buyerIsPrivate (default false).
- Direct sellers: send
buyer_is_private: true. Without a partner key you can't read an account-level token back. - Partners: an account-level token lets several of your sellers charge the same buyer's card. Use seller-level tokens unless you need that.
- Error
603comes only fromget-buyer-key. A seller charges its own account-level token with its MPL as usual. A token that belongs to another seller, or to another partner, returns error605when you charge it.
3. Charge the saved card
Send the buyer_key to generate-sale from your server. The call charges the card at once: there is no payment page, no sale_url, no CVV and no 3D Secure.
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"buyer_key": "BUYERDEMO-BUYERDEMO-BUYERDEMO-1234567",
"sale_price": 5000,
"currency": "ILS",
"product_name": "Repeat order",
"transaction_id": "order-1002",
"sale_callback_url": "https://your-server.example.com/payme/callback",
"language": "en"
}
The response holds the result (abridged):
{
"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_payment_method": "credit-card",
"price": 5000,
"currency": "ILS",
"transaction_id": "order-1002",
"payme_transaction_id": "TRAN1700-000000AA-EXAMPLE1-TXN00001",
"buyer_card_mask": "532610******5846",
"sale_3ds": false
}
A declined charge also returns HTTP 200, with status_code: 1 (abridged):
{
"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-SALE0002",
"sale_status": "failed"
}
- Check
status_code, not the HTTP status. Request errors, such as an unusable token or a field that can't be combined withbuyer_key, also returnstatus_code: 1, with an HTTP error status. - Every call creates a new sale, even when the charge is declined. PayMe doesn't de-duplicate
transaction_id, so a repeated call charges again. After a timeout, look the sale up withget-salesbefore you retry. See Idempotency and Retries. - Callbacks follow as for any sale:
sale-completefor a charge,sale-failurefor a decline. - The token's payment method is used, whatever
sale_payment_methodyou send. - To hold the amount instead of charging it, add
sale_type: authorize. The sale becomesauthorized, and you capture it later: see Authorize now, capture later.
Because the buyer isn't there, nothing is checked with them when you charge: no CVV and no 3D Secure. Charge a saved card only for payments the buyer has agreed to.
4. Get a token back
- From the save itself. The
sale-completecallback of acapture_buyerortokensale carriesbuyer_key.capture-buyer-tokenreturns it in the response, and Hosted Fields returns it fromtokenize(). - If you missed it. Call
get-buyer-keywith thepayme_sale_idof the paid sale that saved the card. For a subscription whose card was entered onsub_url, sendsub_payme_id: subscription calls and callbacks never return thebuyer_key. - Same card, same key. Saving the same card again for the same buyer and seller can return the
buyer_keyyou already have. Store one record perbuyer_key.
5. Store tokens safely
- Treat
buyer_keylike a card number. With the seller's MPL it charges the card. Store it encrypted, on your server only. - Keep it out of the browser. Never send
buyer_keyor the MPL to a web page or an app, and keep both out of URLs and logs. - Store what you show, not the card. Keep
buyer_card_maskand the expiry next to the token, so the buyer can see which card is on file. Never store the card number or the CVV: you don't need them. - Record how it was saved: which seller saved it, and whether it is permanent and seller-level.
- When a buyer removes a card, delete the
buyer_keyon your side and stop charging it.
6. Keep saved cards up to date (Card Updater)
Cards expire, and card companies replace lost or stolen ones. A charge on the old card then fails, and you have to save the new card and replace the stored buyer_key.
With the Card Updater service active on the seller's account, PayMe updates saved cards when an Israeli card company reports a replacement card. The buyer_key stays the same, so stored tokens and subscriptions keep working. The new masked number and expiry show the next time you read the token with get-buyer-key. PayMe sends no callback when it updates a card. To activate Card Updater, contact PayMe.
Errors
| Code | When | What to do |
|---|---|---|
601 |
buyer_key sent with capture_buyer |
Send one or the other. |
602 |
buyer_key sent with sale_type token or seller-token |
Charge with a regular sale type. |
606 |
buyer_key sent with sale_type: template |
A template can't be charged with a token. |
357 |
buyer_key sent with sale_type: multi-capture |
Capture the original authorization instead. |
604 |
The token is inactive, or a single-use token was already charged | Save the card again, as a permanent token. |
605 |
The token belongs to another seller or another partner | Charge with the seller that saved it. |
603 |
get-buyer-key with seller_payme_id for an account-level token |
Send payme_client_key instead. |
600 |
get-buyer-key found no saved card on the sale or subscription, or the sale isn't paid |
Check the ID, and that the sale was paid. |
130 |
The charge is over the seller's processing limit | Contact PayMe. |
4 |
Saving isn't supported for the sale's payment method | Use one of the methods listed in step 1. |
608 |
buyer_perform_validation sent without capture_buyer or a token sale |
Remove it, or save a card in the same request. |
A decline code, for example 20004 |
The card issuer declined the charge (HTTP 200, status_code: 1) |
Ask the buyer for another card. |
All codes: Errors.
Test it in the sandbox
- Save and charge with
5326105300985846, expiry12/30, CVV658, social ID008336174. It's a local Israeli card that accepts ILS only. 4000000000000036saves through Hosted Fields orcapture-buyer-token, and a later charge with its token is declined with20004. On a payment page withcapture_buyerorsale_type: token, it's declined at once and no token is saved.- To see the single-use rule, save a card with
capture-buyer-tokenwithoutbuyer_is_permanentand charge it twice: the second charge returns604. - Save and charge sandbox tokens with sandbox credentials on
https://sandbox.payme.io.
More cards: Test Cards and Payment Methods.