# Subscription payment creation (recurring) Recurring SBP payments let you automatically charge a customer's bank account without their repeated involvement. The account is identified by a **token** issued during the initial binding. Contact your 1Payment account manager to enable this feature for your project. ## How it works The SBP subscription flow consists of four steps: 1. **Account binding (first request)** — you complete a successful payment with an amount **greater than `0`** and `subscribe=1` via the [payment form](./init-form.md) or [GATE](./host2host.md). The payer confirms binding in the bank app. 2. **Receiving the token** — after bank confirmation, 1Payment sends a callback with a unique `token`. Store it for subsequent charges. 3. **Automatic charge (recurring)** — for repeat payments, your server calls GATE (`init_payment`) with the stored `token`. The charge completes without payer involvement. 4. **Notification** — after each charge attempt, a callback arrives with the final transaction result. ## Technical details | Stage | Endpoint | Methods | | --- | --- | --- | | Subscription registration (form) | `https://api.1payment.com/init_form` | `GET`, `POST` | | Subscription registration (GATE) | `https://api.1payment.com/init_payment` | `GET`, `POST` | | Recurring charge (GATE) | `https://api.1payment.com/init_payment` | `POST` (recommended), `GET` | Response format: **JSON**. For SBP, specify `payment_type=sbp` in requests. ## 1. Subscription registration (first request) To register a subscription, complete a **successful payment** with an amount **greater than `0`** and `subscribe=1`. See [Form payment creation](./init-form.md) and [Host-to-host payment creation (GATE)](./host2host.md) for form and GATE parameters. Below is the required set for binding. ### Required parameters (initiation) | Parameter | Type | Description | | --- | --- | --- | | `partner_id` | Integer | Your unique ID in the 1Payment system. | | `project_id` | Integer | Your project identifier. | | `amount` | Number | Payment amount for binding — greater than `0` (for example, `50.00`). | | `subscribe` | Integer | Subscription creation flag. Always `1`. | | `payment_type` | String | For SBP, always `sbp`. | | `user_data` | String | Your unique order ID for matching. | | `shop_url` | String | URL of the site where the purchase is made. | | `sign` | String | Request signature (see below). | ### Optional parameters (initiation) | Parameter | Type | Description | | --- | --- | --- | | `description` | String | Subscription description for the customer. | | `success_url` | String | Customer redirect URL on success. | | `failure_url` | String | Customer redirect URL on error. | | `user_id` | String | Payer ID in your system. | **Signature for form registration** — prefix `init_form`. **Via GATE** — prefix `init_payment`. ```text MD5(init_form + <параметры_без_sign_в_алфавитном_порядке_через_&> + ) ``` ```text MD5(init_payment + <параметры_без_sign_в_алфавитном_порядке_через_&> + ) ``` ## 2. Recurring charge (repeat payments) To charge automatically, send a GATE request with the stored `token`. With an active subscription, customer involvement is not required. ### Required parameters (recurring) | Parameter | Type | Description | | --- | --- | --- | | `partner_id` | Integer | Your unique ID in the 1Payment system. | | `payment_type` | String | Always `sbp`. | | `project_id` | Integer | Your project identifier. | | `amount` | Number | Amount of the recurring charge (for example, `50.00`). | | `token` | String | Token received during subscription registration (from the callback). | | `user_data` | String | New unique transaction ID. | | `shop_url` | String | URL of the payment source site. | | `sign` | String | Request signature (prefix `init_payment`). | ### Signature generation (`sign`) ```text MD5(init_payment + <параметры_без_sign_в_алфавитном_порядке_через_&> + ) ``` ### Signature verification (recurring charge) {% signatureVerifier method="init_payment" preset="sbp_recurring_payment" /%} ## Request examples {% codeTabs %} {% tab label="Node.js" %} ```javascript const crypto = require('crypto'); const axios = require('axios'); // 1. Инициация подписки (первичная привязка) async function setupSbpSubscription(apiKey, params) { const sortedKeys = Object.keys(params).sort(); const queryString = sortedKeys.map((k) => `${k}=${params[k]}`).join('&'); const baseString = `init_form${queryString}${apiKey}`; params.sign = crypto.createHash('md5').update(baseString).digest('hex'); const response = await axios.post('https://api.1payment.com/init_form', params); return response.data; // ссылка для подтверждения в приложении банка } // 2. Рекуррентное списание (по токену) async function chargeSbpByToken(apiKey, params) { const sortedKeys = Object.keys(params).sort(); const queryString = sortedKeys.map((k) => `${k}=${params[k]}`).join('&'); const baseString = `init_payment${queryString}${apiKey}`; params.sign = crypto.createHash('md5').update(baseString).digest('hex'); const response = await axios.post('https://api.1payment.com/init_payment', params); return response.data; } const secretKey = process.env.ONEPAYMENT_API_KEY; // Пример: привязка const setupData = { partner_id: 1234, project_id: 5678, amount: '50.00', subscribe: 1, payment_type: 'sbp', user_data: 'sbp_setup_777', shop_url: 'http://myshop.ru', }; // setupSbpSubscription(secretKey, setupData).then(console.log); // Пример: списание const recurringData = { partner_id: 1234, payment_type: 'sbp', project_id: 5678, token: 'sbp_t_1a2b3c', amount: '500.00', user_data: 'sbp_order_888', shop_url: 'http://myshop.ru', }; chargeSbpByToken(secretKey, recurringData).then(console.log); ``` {% /tab %} {% tab label="Python" %} ```python import hashlib import os import requests def charge_sbp_by_token(api_key: str, params: dict) -> dict: # 1. Сортировка параметров sorted_keys = sorted(params.keys()) query_string = "&".join(f"{k}={params[k]}" for k in sorted_keys) # 2. Подпись init_payment base_string = f"init_payment{query_string}{api_key}" params["sign"] = hashlib.md5(base_string.encode("utf-8")).hexdigest() # 3. POST-запрос (рекуррент) response = requests.post("https://api.1payment.com/init_payment", data=params) response.raise_for_status() return response.json() api_key = os.environ["ONEPAYMENT_API_KEY"] data = { "partner_id": 1234, "payment_type": "sbp", "project_id": 5678, "token": "sbp_t_1a2b3c", "amount": "500.00", "user_data": "sbp_order_888", "shop_url": "http://myshop.ru", } print(charge_sbp_by_token(api_key, data)) ``` {% /tab %} {% tab label="PHP" %} ```php $v) { if ($k === 'sign') { continue; } $tail .= "{$k}={$v}&"; } $tail = substr($tail, 0, -1); // 2. Формирование подписи (префикс init_payment) $params['sign'] = md5('init_payment' . $tail . $apiKey); // 3. Запрос к API $ch = curl_init('https://api.1payment.com/init_payment'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); return $response; } // Пример данных запроса $apiKey = getenv('ONEPAYMENT_API_KEY'); $data = [ 'partner_id' => 1234, 'payment_type' => 'sbp', 'project_id' => 5678, 'token' => 'sbp_t_1a2b3c', 'amount' => '500.00', 'user_data' => 'sbp_order_888', 'shop_url' => 'http://myshop.ru', ]; echo chargeSbpByToken($apiKey, $data); ``` {% /tab %} {% tab label="cURL" %} ```bash # Рекуррент: sign = md5("init_payment" + amount=500.00&partner_id=1234&payment_type=sbp&project_id=5678&shop_url=...&token=...&user_data=... + API_KEY) curl -sS -X POST "https://api.1payment.com/init_payment" \ -d "partner_id=1234&payment_type=sbp&project_id=5678&token=sbp_t_1a2b3c&amount=500.00&user_data=sbp_order_888&shop_url=http%3A%2F%2Fmyshop.ru&sign=PASTE_MD5_HEX" ``` {% /tab %} {% /codeTabs %} ## API response On a successful **recurring** request (`200`): ```json { "order_id": "8p3brmb19gfg0sg8gcwhws8kgc748s87", "status": 2, "status_description": "PENDING" } ``` For **form registration**, the response includes `url` (see [Form payment creation](./init-form.md)); via GATE — `redirect_url` (see [Host-to-host payment creation (GATE)](./host2host.md)). Request error (`400`): ```json { "error_code": 2 } ``` ## Status notifications (callbacks) On successful binding or charge, the system sends a **POST** request in JSON format to your `notify_url`. | Parameter | Type | Req. | Description | | --- | --- | --- | --- | | `payment_type` | String | Yes | Payment type (`sbp`). | | `order_id` | String | Yes | Payment ID in the 1Payment system. | | `project_id` | Integer | Yes | Your project ID. | | `status` | Integer | Yes | State: `3` (success), `4` (failure). | | `status_description` | String | Yes | `SUCCESS` or `FAILURE`. | | `init_time` | String | Yes | Payment creation time. | | `status_time` | String | Yes | Time the final status was received. | | `merchant_price` | Number | Yes | Amount for the payer. | | `init_price` | Number | Yes | Amount at initiation. | | `user_price` | Number | Yes | Amount credited to the partner. | | `currency` | String | Yes | Currency (ISO 4217). | | `account` | String | Yes | For SBP — `sbp`. | | `user_data` | String | Yes | Your transaction ID passed at creation. | | `sign` | String | Yes | Callback signature. | | `token` | String | No | Token for subsequent charges — **store** it during binding. | | `test` | Integer | No | `1` for test transactions. | | `status_code` | String | No | Decline reason code. | **Important:** your server must return **HTTP 200 OK**. Otherwise the system retries the callback **once per minute for 10 minutes**. **Callback signature verification:** MD5 of parameters in alphabetical order joined by `&` + `API_KEY` (**without** the `init_payment` prefix). See [API request format](../init-request.md#callbacks-notifications). ## Related sections - [Form payment creation](./init-form.md) - [Host-to-host payment creation (GATE)](./host2host.md) - [Payment status](./status.md) - [Payment refunds](./refund.md) - [Transaction statuses](../transaction-statuses.md) - [Error codes (API)](../error-codes-api.md) - [Decline error codes](../decline-error-codes.md)