# Build recurring billing with subscriptions Building with an AI agent? Start at https://docs.payme.io/agents.md ## 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](/payments/subscriptions/post-generate-subscription) - [Pay a subscription](/payments/subscriptions/post-generate-subscription-2) - [Pause a subscription](/payments/subscriptions/post-pause-subscription) - [Resume a subscription](/payments/subscriptions/patch-subscriptions-sub-payme-id-resume) - [Cancel a subscription](/payments/subscriptions/postcancel-subscription) - [Update a subscription's price](/payments/subscriptions/patch-subscriptions-sub-id-set-price) - [List subscriptions](/payments/query-apis/post-get-subscriptions) - [List sales](/payments/query-apis/post-get-sales) - [Save a card and charge it later](/accepting-payments/capture-and-saved-cards/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-subscription`](/payments/subscriptions/post-generate-subscription) needs the seller's `seller_payme_id` (MPL) in the JSON body; the `PayMe-Merchant-Key` header alone isn't enough there. Partners also send `payme_client_key`. See [Authentication](/payments/getting-started/authentication). - **Base URL.** `https://sandbox.payme.io/api/` in the sandbox, `https://live.payme.io/api/` in production. - **A callback URL.** Send `sub_callback_url` when 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. `localhost` and private IP addresses are refused with error `21`. ## 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](/accepting-payments/capture-and-saved-cards/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`](/payments/subscriptions/post-generate-subscription): ```json { "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_price` is the price of one iteration, in minor units (`5000` = 50.00). - `sub_iteration_type`: `1` daily, `2` weekly, `3` monthly, `4` yearly, `5` quarterly. See [Subscription iteration types](/payments/codes-statuses/subscription-iteration-types). - `sub_iterations`: `-1` (the default) for no end, or 1–54. - `sub_start_date` is the date of the first charge, `DD/MM/YYYY`. The default is today. It can't be in the past (error `374`), and a monthly subscription must start on day 1–28 (error `375`). - `subscription_id` is 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`](/payments/subscriptions/post-generate-subscription-2) 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_date` holds the time of the charge, and `sub_iterations_completed` goes up by one; - `sub_next_date` moves to the next iteration. It is always counted from `sub_start_date`, so the billing day doesn't drift; - PayMe sends `sub-iteration-success`, with the new sale's `payme_sale_id` and `payme_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: 1. **From the callback.** When `sub-iteration-success` arrives, store its `payme_sale_id` against the `sub_payme_id`. Refunds and reports work on the sale. 2. **From a query.** Call [`get-sales`](/payments/query-apis/post-get-sales) with `sale_type` `3` and `sale_parent_code` set to the subscription's `sub_payme_code`. The result also lists failed attempts (`sale_status` `failed`); send `sale_status` to narrow it. ```json { "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-failure` carries `sub_error_text`, the decline message with its code in brackets. It carries no sale ID and no attempt counter. Each failed attempt is a `failed` sale, which you can list with `get-sales` as in step 4. - When a retry succeeds, PayMe sends `sub-iteration-success` and the status returns to `2`. The billing day doesn't change. - **To recover sooner,** have the buyer enter a new card: `sub_url` opens again while the status is `1`, `4` or `7`, or you can call `pay-subscription`. The new card is checked and saved, and the status becomes `2`. Nothing is charged at that moment: the job charges at `sub_next_date`, which for a status-`7` subscription 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](/payments/subscriptions/post-pause-subscription): `POST /pause-subscription` | `2`, `4`, `7` | Status `3`. Nothing is charged. | `sub-pause` | | [Resume](/payments/subscriptions/patch-subscriptions-sub-payme-id-resume): `PATCH /subscriptions/{sub_payme_id}/resume` | `3` | Status `2`. The next charge runs at `sub_next_date`. | None | | [Cancel](/payments/subscriptions/postcancel-subscription): `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`, reduces `sub_iterations_left`, and PayMe sends `sub-iteration-skipped`. Skipped iterations are never charged, not even after you resume. If every remaining iteration is skipped, the subscription becomes `6` (Completed) while still paused. - **A paused subscription can't be canceled:** `cancel-subscription` returns error `305`. Resume it, then cancel it right away. - A canceled subscription can't be reactivated. Create a new one. - After a cancel, `sub_next_date` keeps 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-`4` subscription 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`](/payments/subscriptions/patch-subscriptions-sub-id-set-price) with the new `sub_price`, for example `PATCH https://sandbox.payme.io/api/subscriptions/SUB16885-68336QPL-UQSSS1CC-SYKXI53N/set-price`: ```json { "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 status `1`, or a status-`1` subscription whose `sub_start_date` is still in the future. Anything else returns error `377` (HTTP 400). - The path takes `sub_payme_id`. Your own `subscription_id` returns error `371`. - 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`](/payments/tokenization/post-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 `4` or `7`).** Send the buyer back to `sub_url`, or call `pay-subscription` with the new card. The new card replaces the old one. - **An active subscription.** No documented call replaces its card. Contact PayMe at . 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_type` `2`) with its own `sub_payme_id`, and PayMe sends `sub-create` and then `sub-active` for it. - A buyer's subscription copies the template's price, schedule, `sub_callback_url` and `subscription_id`. Tell buyers apart by `sub_payme_id`. - To list the buyers' subscriptions, call [`get-subscriptions`](/payments/query-apis/post-get-subscriptions) with `sub_parent_code` set to the template's `sub_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-price` on 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`](/payments/query-apis/post-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](/payments/getting-started/callbacks#subscriptions). ## Test it in the sandbox - **A working subscription.** Create one that starts today and pay its `sub_url` with `5326105300985846`, expiry `12/30`, CVV `658`. You receive `sub-create`, `sub-active`, then `sub-iteration-success` when the first charge runs. - **A failed renewal.** Save `4000000000000036` with `capture-buyer-token` and `buyer_is_permanent: true` (or with Hosted Fields), then create a monthly subscription with that `buyer_key`. Its scheduled charge is declined with `20004`, so the subscription moves to status `7` and you receive `sub-failure`. - Later renewals and retries follow the real schedule: no call charges an iteration early. More cards: [Test Cards and Payment Methods](/payments/getting-started/test-cards-and-payment-methods). ## See also - [Subscriptions overview](/payments/subscriptions): endpoints, statuses and iteration types. - [Subscription statuses](/payments/codes-statuses/subscription-statuses) - [List subscriptions](/payments/query-apis/post-get-subscriptions)