Build recurring billing with subscriptions
Prerequisites
- Seller's seller_payme_id (MPL), sent in the JSON body
- A public HTTPS URL for sub_callback_url (not localhost or a private IP)
- For the saved-card model: a permanent buyer_key
Related
- Create a subscription
- Pay a subscription
- Pause a subscription
- Resume a subscription
- Cancel a subscription
- Update a subscription's price
- List subscriptions
- List sales
- Save a card and charge it later
A subscription charges a buyer's saved card on a fixed schedule (daily, weekly, monthly, quarterly or yearly) for a set number of iterations or until you cancel it. PayMe runs the schedule, retries failed charges and reports each step with a callback. You create the subscription, keep your records in sync from the callbacks, and pause, reprice or cancel it through the API.
Each iteration is charged separately; nothing is authorized up front. Wallets such as Apple Pay, Google Pay and Bit aren't offered for subscriptions.
This guide follows a subscription from creation to its last charge. The fields of each call are on the endpoint pages linked in each step.
Before you start
- Credentials.
generate-subscriptionneeds the seller'sseller_payme_id(MPL) in the JSON body; thePayMe-Merchant-Keyheader alone isn't enough there. Partners also sendpayme_client_key. See Authentication. - Base URL.
https://sandbox.payme.io/api/in the sandbox,https://live.payme.io/api/in production. - A callback URL. Send
sub_callback_urlwhen you create the subscription: no call changes it later. Without it, callbacks go to your partner's default callback URL, if one is set; a seller has no such setting.localhostand private IP addresses are refused with error21.
Choose how the buyer signs up
| Model | How | Use it when |
|---|---|---|
| Payment link | Create the subscription and send the buyer to its sub_url to enter a card. |
You don't have the buyer's card yet. |
| Saved card | Save a permanent card first, then create the subscription with its buyer_key. |
The buyer already paid you, or you collect cards in your own checkout. |
| Template link | Create one subscription with sub_type 10 and share its sub_url. Each buyer who pays it gets their own subscription. |
One public sign-up link for many buyers, for example on social media. |
How to save a permanent card: Save a card and charge it later.
Charge now, then every month. Charge the first payment as a regular sale with capture_buyer: 1, which also saves the card. Then create the subscription with that buyer_key and sub_start_date one period later (for a monthly plan, a day from 1 to 28). Nothing is charged before sub_start_date, so the buyer isn't charged twice.
1. Create the subscription
Call generate-subscription:
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sub_price": 5000,
"sub_currency": "ILS",
"sub_description": "Monthly plan",
"sub_iteration_type": 3,
"sub_iterations": 12,
"sub_start_date": "01/12/2026",
"subscription_id": "order-1001",
"sub_callback_url": "https://www.example.com/payment/callback",
"sub_return_url": "https://www.example.com/payment/success",
"language": "en"
}
sub_priceis the price of one iteration, in minor units (5000= 50.00).sub_iteration_type:1daily,2weekly,3monthly,4yearly,5quarterly. See Subscription iteration types.sub_iterations:-1(the default) for no end, or 1–54.sub_start_dateis the date of the first charge,DD/MM/YYYY. The default is today. It can't be in the past (error374), and a monthly subscription must start on day 1–28 (error375).subscription_idis your own reference. It isn't unique: sending the same value twice creates two subscriptions.
The response returns the subscription in status 1 (Initial), with its sub_url, sub_payme_id and sub_payme_code. Store sub_payme_id: every other subscription call uses it. PayMe sends sub-create.
With a saved card, add a permanent buyer_key and skip sub_url. The subscription is created in status 2 (Active) at once, and PayMe also sends sub-active. A single-use token returns error 376. A template can't take a buyer_key.
2. The buyer pays and the subscription starts
On sub_url the buyer enters a card. PayMe checks the card and saves it; nothing is charged yet. The subscription moves to status 2 (Active), PayMe sends sub-active, and the buyer is sent to sub_return_url if you set one. If you are PCI DSS Level 1 certified and collect the card in your own form, send it with pay-subscription instead.
A background job that runs once a minute makes every charge, including the first. The first charge runs within about a minute after sub_start_date, once a card is attached.
If the card check fails, the subscription moves to status 4 (Failed) and PayMe sends sub-failure. PayMe doesn't retry it and doesn't cancel it. The buyer can open sub_url again and enter another card, or you can send one with pay-subscription.
3. Each charge
When sub_next_date arrives, PayMe charges the saved card, with no CVV and no 3D Secure. Every attempt creates a sale of type 3 (SaleFromSubscription). When the charge succeeds:
- the subscription is in status
2; sub_prev_dateholds the time of the charge, andsub_iterations_completedgoes up by one;sub_next_datemoves to the next iteration. It is always counted fromsub_start_date, so the billing day doesn't drift;- PayMe sends
sub-iteration-success, with the new sale'spayme_sale_idandpayme_sale_code.
After the last iteration the status becomes 6 (Completed) and PayMe sends sub-complete.
4. Link each charge to its subscription
A renewal sale doesn't name its subscription, and its own sale callbacks don't go to sub_callback_url (only to your partner's default callback URL, if one is set). Link charges in one of two ways:
- From the callback. When
sub-iteration-successarrives, store itspayme_sale_idagainst thesub_payme_id. Refunds and reports work on the sale. - From a query. Call
get-saleswithsale_type3andsale_parent_codeset to the subscription'ssub_payme_code. The result also lists failed attempts (sale_statusfailed); sendsale_statusto narrow it.
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sale_type": 3,
"sale_parent_code": 477004
}
The sub-iteration-success fields you need:
| Field | Example | Use |
|---|---|---|
notify_type |
sub-iteration-success |
What happened. |
sub_payme_id |
SUB16885-68336QPL-UQSSS1CC-SYKXI53N |
The subscription. |
subscription_id |
order-1001 |
Your reference, if you sent one. |
payme_sale_id |
SALE1700-000000AA-EXAMPLE1-SALE0001 |
The sale this charge created. |
payme_sale_code |
12345678 |
The same sale's numeric code. |
sub_price |
5000 |
The amount charged, in minor units. |
sub_prev_date |
2026-12-01 00:01:00 |
When the charge ran. |
sub_next_date |
2027-01-01 00:00:00 |
When the next charge is due. |
sub_iterations_completed, sub_iterations_left |
1, 11 |
Progress. |
5. Handle failed charges
| What failed | Status | Callback | What PayMe does next |
|---|---|---|---|
| The card check when the buyer pays | 4 Failed |
sub-failure |
Nothing: the buyer must pay again. |
| A scheduled charge, with a retry left | 7 Failed, retry pending |
sub-failure |
Moves sub_next_date one day ahead and tries again. |
| A scheduled charge of a daily subscription, or the seventh failure in a row | 5 Canceled |
sub-cancel, without sub-failure |
Nothing: the subscription is over, and sub_next_date becomes null. |
- PayMe makes at most 7 attempts per charge, one a day: the original and 6 retries. This limit is fixed and can't be changed per account or per subscription.
sub-failurecarriessub_error_text, the decline message with its code in brackets. It carries no sale ID and no attempt counter. Each failed attempt is afailedsale, which you can list withget-salesas in step 4.- When a retry succeeds, PayMe sends
sub-iteration-successand the status returns to2. The billing day doesn't change. - To recover sooner, have the buyer enter a new card:
sub_urlopens again while the status is1,4or7, or you can callpay-subscription. The new card is checked and saved, and the status becomes2. Nothing is charged at that moment: the job charges atsub_next_date, which for a status-7subscription is the next retry date. - No call charges an iteration on demand.
- These charge retries are separate from callback delivery, which PayMe retries 3 times within about 90 seconds.
6. Pause, resume and cancel
| Call | Allowed in status | Result | Callback |
|---|---|---|---|
Pause: POST /pause-subscription |
2, 4, 7 |
Status 3. Nothing is charged. |
sub-pause |
Resume: PATCH /subscriptions/{sub_payme_id}/resume |
3 |
Status 2. The next charge runs at sub_next_date. |
None |
Cancel: POST /cancel-subscription |
1, 2, 4, 7 |
Status 5. Final. |
sub-cancel |
- While a subscription is paused, each iteration whose date passes is skipped: it counts in
sub_iterations_skipped, reducessub_iterations_left, and PayMe sendssub-iteration-skipped. Skipped iterations are never charged, not even after you resume. If every remaining iteration is skipped, the subscription becomes6(Completed) while still paused. - A paused subscription can't be canceled:
cancel-subscriptionreturns error305. Resume it, then cancel it right away. - A canceled subscription can't be reactivated. Create a new one.
- After a cancel,
sub_next_datekeeps its old value. Ignore it. - Cancelling emails the buyer. Buyers can't cancel on their own: the seller cancels, through the API or in the dashboard.
- Don't pause a status-
4subscription to fix it: it has no working card. Have the buyer pay again instead. - A status the call doesn't accept returns error
305: HTTP 400 on resume, HTTP 500 on pause and cancel.
7. Change the price
Call PATCH /subscriptions/{sub_payme_id}/set-price with the new sub_price, for example PATCH https://sandbox.payme.io/api/subscriptions/SUB16885-68336QPL-UQSSS1CC-SYKXI53N/set-price:
{
"seller_payme_id": "MPLDEMO-MPLDEMO-MPLDEMO-1234567",
"sub_price": 7500
}
- The new price applies to future iterations. Nothing is charged, and
sub_next_date,sub_start_date, the counters and the status don't change. - You can update an active subscription (status
2), a template in status1, or a status-1subscription whosesub_start_dateis still in the future. Anything else returns error377(HTTP 400). - The path takes
sub_payme_id. Your ownsubscription_idreturns error371. - If the price changed and the subscription has a buyer email, PayMe emails the buyer about the new price, subject to the seller's email settings.
Mid-cycle upgrade. There is no proration. Work out the difference yourself, for example (new price − old price) × days left ÷ days in the cycle. Charge it once with generate-sale and the subscription's buyer_key (read it with get-buyer-key and sub_payme_id), then call set-price. The next cycle charges the full new price on the same billing day. Don't cancel and re-create the subscription: that resets sub_start_date and the counters.
8. Change the card
- A failing subscription (status
4or7). Send the buyer back tosub_url, or callpay-subscriptionwith the new card. The new card replaces the old one. - An active subscription. No documented call replaces its card. Contact PayMe at partners@payme.io.
If you can't wait, move the buyer to a new subscription: save the new card as a permanent token, create a subscription with that buyer_key and sub_start_date set to the old subscription's sub_next_date, then cancel the old one before that date. The new subscription has its own sub_payme_id and counters, so set sub_iterations to the iterations left. Cancelling the old one sends sub-cancel and emails the buyer.
9. Share one link with many buyers (templates)
A template (sub_type 10) is one payment link for many buyers. Send the number 10: the text template is rejected with error 24.
- Share the template's
sub_url. Each buyer who pays it gets a new subscription (sub_type2) with its ownsub_payme_id, and PayMe sendssub-createand thensub-activefor it. - A buyer's subscription copies the template's price, schedule,
sub_callback_urlandsubscription_id. Tell buyers apart bysub_payme_id. - To list the buyers' subscriptions, call
get-subscriptionswithsub_parent_codeset to the template'ssub_payme_code. - The link works while the template is in status
1. Cancelling the template closes the link; subscriptions already created from it keep running, and you cancel them one by one. set-priceon the template changes the price for buyers who join afterwards. Subscriptions already created keep their price.
Callbacks
notify_type |
When |
|---|---|
sub-create |
The subscription was created. |
sub-active |
A card was attached and the subscription is active. |
sub-iteration-success |
A charge succeeded. Carries payme_sale_id and payme_sale_code. |
sub-failure |
The card check failed (status 4), or a scheduled charge failed and will be retried (status 7). |
sub-pause |
The subscription was paused. |
sub-iteration-skipped |
An iteration date passed while the subscription was paused. |
sub-complete |
The last iteration was charged or skipped. |
sub-cancel |
The subscription was canceled, by the seller or automatically. |
Subscription callbacks are form-encoded POST requests to sub_callback_url. They carry no payme_signature: before acting on one, confirm the state with get-subscriptions and sub_payme_id. They never contain the buyer_key. The same callback can arrive more than once, so process each one once; for sub-iteration-success, de-duplicate on payme_sale_id. Dates are Asia/Jerusalem local time. Every field: Callbacks → Subscriptions.
Test it in the sandbox
- A working subscription. Create one that starts today and pay its
sub_urlwith5326105300985846, expiry12/30, CVV658. You receivesub-create,sub-active, thensub-iteration-successwhen the first charge runs. - A failed renewal. Save
4000000000000036withcapture-buyer-tokenandbuyer_is_permanent: true(or with Hosted Fields), then create a monthly subscription with thatbuyer_key. Its scheduled charge is declined with20004, so the subscription moves to status7and you receivesub-failure. - Later renewals and retries follow the real schedule: no call charges an iteration early.
More cards: Test Cards and Payment Methods.
See also
- Subscriptions overview: endpoints, statuses and iteration types.
- Subscription statuses
- List subscriptions