Aeris API documentation
Reference for authentication, creating payments and payouts, webhook events and status checks.
Download Postman documentationMain sections
- Base URL
https://aeris-psp.net- Data format
application/json
Your first payment
Follow the path from access setup to a confirmed order. Examples use demonstration data; sending them with a production key creates a real operation.
Prerequisites
- Get a project and a public_key / secret_key pair. Use a separate test project for testing.
- Allow your backend’s outgoing IP under API IP. Separately allow your website domain for the widget.
- Prepare an HTTPS webhook handler and return pages. Keep the secret key on your backend only.
Send the request from your backend. Never send the secret key to the browser.
Save id and merchant_order_id. pending means payment is awaited; payment_url opens the payment page.
Give the customer only payment_url. They choose a bank and confirm payment on that page.
GET uses the saved id. Fulfil the order only after completed from this response or a verified webhook.
How integration works
Choose who controls payment
- Payment page
- Aeris displays the form, QR and bank buttons. Open payment_url or embed the widget.
- Host-to-Host
- Your interface receives a direct URL or next_action. You implement redirects and 3DS handling.
- Shared payment page
- The customer chooses SBP or SberPay. A response containing checkout_id describes a selection session, not a confirmed payment.
merchant_order_id- Your unique order number. Use it to match operations and check a lost response safely.
id- Aeris transaction identifier. Save it from the response for status queries.
project_url- Website or Telegram bot the order belongs to. Not a webhook or return URL.
callback_url- Your backend notification handler. An incoming Aeris request, not customer navigation.
redirect_url_success- Customer return page after the successful flow. Not confirmation that funds have been received.
API keys
The primary key is created with the project. You can issue up to four additional keys in the dashboard. The same section contains the notification URL, server IP/CIDR ranges and HTTPS widget domains. Viewing keys and saving changes requires confirmation through Telegram or an authenticator app.
Settings → API keys
Primary key + up to 4 additional keys
Settings → Webhook and access
Webhook URL → default notification endpoint
API IP → server addresses
Checkout origins → website domainsAuthentication
Every request is signed with HMAC-SHA256. Send the timestamp as Unix seconds within the accepted time window. Serialize JSON compactly without spaces. For GET, send no HTTP body, but include {} in the signature.
body = compact_json_ascii(request_body) # GET: "{}"
message = body + ":" + unix_timestamp + "++"
signature = hex(hmac_sha256(base64(secret_key), message))
X-API-KEY: <public_key>
X-TIMESTAMP: <unix_seconds>
X-SIGNATURE: <signature>- For POST, sign compact JSON with ASCII-escaped Unicode (\uXXXX), as produced by json.dumps(..., separators=(",", ":"), ensure_ascii=True). For GET, send no HTTP body, but use the string {} when computing the signature.
- base64(secret_key) means Base64-encoding the UTF-8 secret string, not decoding it. Use Unix seconds, not milliseconds.
- Sign API requests with a matching primary or additional key pair. Never mix one pair’s public_key with another pair’s secret_key.
Create a paymentSBP, SberPay and bank cards
Payment page
Aeris shows the customer a ready-to-use payment page.
H2H
Your backend receives a direct URL or next_action and controls the interface.
SBP + SberPay
One payment page with the methods available to the customer. A payment is created after a method is selected.
The backend signs the request and stores the operation ID.
Open it as a payment page or pass it to the JS widget.
On desktop, scans the QR code. On mobile, opens the banking app.
Fulfil the order only after completed arrives through webhook or status API.
Aeris payment page
Order payment
Demo StoreRUB 9,000
The result will appear on this page
SBP recurring payments
A subscription stores the agreed price and interval. Aeris or your backend initiates charges; both use the same billing obligations, limits and history.
Paths below start with /api/v1/merchant. Sign requests like ordinary payments. GET /recurring/capabilities returns available methods and billing switches.
Send stable merchant_subscription_id, customer_id, international payer_phone and final discounted terms. initial_amount is the first payment (1 RUB by default); terms.amount is the recurring price. initiator: aeris runs the schedule, merchant waits for your requests. A plan is an optional template; editing it does not change subscriptions.
Give the customer confirmation_url. Aeris displays the initial payment, recurring price, interval and start date. The customer accepts and pays through their bank. awaiting_confirmation ends only after acceptance, successful initial payment and an active binding. There is no automatic initial-payment refund.
Save the subscription id. Wait for status: active using the API or authenticated notifications. A browser redirect is not proof of payment. payment_token identifies a payment method; subscription_id identifies agreed terms and billing history.
Send subscription_id and merchant_order_id. The price and token come from the subscription and cannot be overridden. Repeated requests or different order IDs address the same obligation for that period. Early, paused or blocked charges are not dispatched. Never create another subscription or payment to recover an unknown outcome.
Management and limits
One obligation per period and one unresolved charge. At most three dispatched attempts per rolling 24 hours, at least one hour apart; retries require authoritative failure. Timeouts retain the fence. Missed periods are not collected. Disabling charges blocks API and scheduler admission, not reconciliation.
Include current expected_version for edits/actions. Exceeding the agreed price, changing the interval or extending the consented duration requires new confirmation. Changing initiator preserves history and limits. Pausing/canceling does not refund or recall a dispatched payment.
{
"subscription_id": "e5a0c035-bef2-48a5-b59b-035cbd877eaf",
"expected_version": 2,
"action": "pause"
}{
"id": "e5a0c035-bef2-48a5-b59b-035cbd877eaf",
"merchant_subscription_id": "subscription-10001",
"customer_id": "customer-10001",
"name": "Monthly access",
"payment_token": "938b3f2e-5927-4b4e-85d1-1a4b7e0c9040",
"plan_id": null,
"terms": {
"amount": 990,
"currency": "RUB",
"interval": "month",
"period": 1,
"start_at": "2030-01-31T10:00:00+03:00",
"timezone": "Europe/Moscow",
"end_at": null,
"max_payments": 12,
"customer_fee_percent": "0",
"retry_policy": {
"retry_delays_seconds": [
3600,
86400
],
"on_exhausted": "pause"
}
},
"status": "paused",
"reason": "merchant_request",
"version": 3,
"paid_cycles": 0,
"initiator": "merchant",
"confirmation_url": null,
"next_payment_at": null,
"cancel_at": null,
"project_url": "https://merchant.example",
"consent_reference": "consent-10001",
"created_at": "2029-12-31T10:00:00+00:00",
"preview": [
{
"cycle_number": 0,
"payment_at": "2030-01-31T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
},
{
"cycle_number": 1,
"payment_at": "2030-02-28T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
},
{
"cycle_number": 2,
"payment_at": "2030-03-31T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
}
]
}Subscription with the first payment
Add save_payment_method and recurring to POST /payins/sbp. payment_url opens Aeris agreement confirmation and subscription contains the subscription ID. For an initial discount, send the discounted amount and the regular recurring.amount.
Request and code
# Set PUBLIC_KEY and SECRET_KEY in your environment first.
: "${PUBLIC_KEY:?Set PUBLIC_KEY}"
: "${SECRET_KEY:?Set SECRET_KEY}"
BODY='{"amount":100,"currency":"RUB","merchant_order_id":"recurring-first-10001","payer_ip":"203.0.113.10","project_url":"https://merchant.example","callback_url":"https://merchant.example/webhooks/payment","redirect_url_success":"https://merchant.example/payment/success","save_payment_method":true,"customer_id":"customer-10001","consent_granted":true,"consent_reference":"consent-10001","subscription_purpose":"Monthly access","payer_phone":"+79991234567","recurring":{"amount":990,"currency":"RUB","interval":"month","period":1,"start_at":"2030-01-31T10:00:00+03:00","timezone":"Europe/Moscow","max_payments":12,"customer_fee_percent":0,"retry_policy":{"retry_delays_seconds":[3600,86400],"on_exhausted":"pause"},"merchant_subscription_id":"subscription-first-10001"}}'
TIMESTAMP=$(date +%s)
HMAC_KEY=$(printf '%s' "$SECRET_KEY" | openssl base64 -A)
SIGNATURE=$(printf '%s' "$BODY:$TIMESTAMP++" | openssl dgst -sha256 -hmac "$HMAC_KEY" -r | cut -d ' ' -f 1)
curl --fail-with-body --request POST \
"https://aeris-psp.net/api/v1/merchant/payins/sbp" \
--header "Content-Type: application/json" \
--header "X-API-KEY: $PUBLIC_KEY" \
--header "X-TIMESTAMP: $TIMESTAMP" \
--header "X-SIGNATURE: $SIGNATURE" \
--data-raw "$BODY"{
"id": "5ce82d35-c78e-4181-b39b-e004421952ef",
"merchant_order_id": "recurring-first-10001",
"amount": 100,
"order_amount": 100,
"customer_fee_amount": 0,
"status": "pending",
"currency": "RUB",
"payment_method": "sbp",
"payment_url": "https://aeris-psp.net/checkout?session=RESPONSE_SESSION",
"next_action": null,
"payment_token": "938b3f2e-5927-4b4e-85d1-1a4b7e0c9040",
"payment_token_status": "pending",
"subscription": {
"id": "e5a0c035-bef2-48a5-b59b-035cbd877eaf",
"merchant_subscription_id": "subscription-first-10001",
"customer_id": "customer-10001",
"name": "",
"payment_token": "938b3f2e-5927-4b4e-85d1-1a4b7e0c9040",
"plan_id": null,
"terms": {
"amount": 990,
"currency": "RUB",
"interval": "month",
"period": 1,
"start_at": "2030-01-31T10:00:00+03:00",
"timezone": "Europe/Moscow",
"end_at": null,
"max_payments": 12,
"customer_fee_percent": "0",
"retry_policy": {
"retry_delays_seconds": [
3600,
86400
],
"on_exhausted": "pause"
}
},
"status": "awaiting_confirmation",
"reason": "",
"version": 1,
"paid_cycles": 0,
"initiator": "aeris",
"confirmation_url": "https://aeris-psp.net/checkout?session=RESPONSE_SESSION",
"next_payment_at": null,
"cancel_at": null,
"project_url": "https://merchant.example",
"consent_reference": "consent-10001",
"created_at": "2029-12-31T10:00:00+00:00",
"preview": [
{
"cycle_number": 0,
"payment_at": "2030-01-31T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
},
{
"cycle_number": 1,
"payment_at": "2030-02-28T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
},
{
"cycle_number": 2,
"payment_at": "2030-03-31T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
}
]
}
}H2H without the Aeris window
Requires separate Aeris approval and acceptance of the terms. In POST /recurring/subscriptions send confirmation_mode: merchant, explicit consent_granted: true and consent_evidence. consent_reference identifies your evidence archive; document_sha256 is the SHA-256 of the full terms document, not an arbitrary string. accepted_at is the original consent timestamp with UTC offset; keep it unchanged on retries. Without approval, the response is HTTP 403.
Display the exact initial and recurring amounts, interval and duration in your interface. The response contains initial_payment_url for the first bank payment and confirmation_url: null. Merchant attestation alone does not activate a subscription: completed initial SBP payment and an active binding remain mandatory. Supply original evidence of consent to the declared tariff within 24 hours of a request; exceptions and consequences follow the accepted terms.
Request and code
# Set PUBLIC_KEY and SECRET_KEY in your environment first.
: "${PUBLIC_KEY:?Set PUBLIC_KEY}"
: "${SECRET_KEY:?Set SECRET_KEY}"
BODY='{"merchant_subscription_id":"subscription-10001","name":"Monthly access","initiator":"merchant","initial_amount":1,"customer_id":"customer-10001","terms":{"amount":990,"currency":"RUB","interval":"month","period":1,"start_at":"2030-01-31T10:00:00+03:00","timezone":"Europe/Moscow","max_payments":12,"customer_fee_percent":0,"retry_policy":{"retry_delays_seconds":[3600,86400],"on_exhausted":"pause"}},"consent_granted":true,"consent_reference":"consent-10001","payer_ip":"203.0.113.10","payer_phone":"+79991234567","project_url":"https://merchant.example","callback_url":"https://merchant.example/webhooks/payment","confirmation_mode":"merchant","consent_evidence":{"accepted_at":"2026-10-19T10:00:00+03:00","document_version":"tariff-1","document_sha256":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}}'
TIMESTAMP=$(date +%s)
HMAC_KEY=$(printf '%s' "$SECRET_KEY" | openssl base64 -A)
SIGNATURE=$(printf '%s' "$BODY:$TIMESTAMP++" | openssl dgst -sha256 -hmac "$HMAC_KEY" -r | cut -d ' ' -f 1)
curl --fail-with-body --request POST \
"https://aeris-psp.net/api/v1/merchant/recurring/subscriptions" \
--header "Content-Type: application/json" \
--header "X-API-KEY: $PUBLIC_KEY" \
--header "X-TIMESTAMP: $TIMESTAMP" \
--header "X-SIGNATURE: $SIGNATURE" \
--data-raw "$BODY"{
"id": "e5a0c035-bef2-48a5-b59b-035cbd877eaf",
"merchant_subscription_id": "subscription-10001",
"customer_id": "customer-10001",
"name": "Monthly access",
"payment_token": "938b3f2e-5927-4b4e-85d1-1a4b7e0c9040",
"plan_id": null,
"terms": {
"amount": 990,
"currency": "RUB",
"interval": "month",
"period": 1,
"start_at": "2030-01-31T10:00:00+03:00",
"timezone": "Europe/Moscow",
"end_at": null,
"max_payments": 12,
"customer_fee_percent": "0",
"retry_policy": {
"retry_delays_seconds": [
3600,
86400
],
"on_exhausted": "pause"
}
},
"status": "awaiting_confirmation",
"reason": "",
"version": 1,
"paid_cycles": 0,
"initiator": "merchant",
"confirmation_url": null,
"next_payment_at": null,
"cancel_at": null,
"project_url": "https://merchant.example",
"consent_reference": "consent-10001",
"created_at": "2029-12-31T10:00:00+00:00",
"preview": [
{
"cycle_number": 0,
"payment_at": "2030-01-31T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
},
{
"cycle_number": 1,
"payment_at": "2030-02-28T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
},
{
"cycle_number": 2,
"payment_at": "2030-03-31T07:00:00+00:00",
"amount": 990,
"currency": "RUB"
}
],
"confirmation_mode": "merchant",
"initial_payment_url": "https://bank.example/sbp/enrollment"
}Notifications and dashboard
A signed payment webhook with status: completed confirms payment. Linked charges include subscription_id, invoice_id, attempt_id and payment_token. recurring.subscription.* events describe lifecycle, not payment completion. Dashboard → Recurring payments contains plans, subscriptions, invoices and methods; changes require OTP.
GET /api/v1/merchant/recurring/settings
GET /api/v1/merchant/recurring/plans
GET /api/v1/merchant/recurring/subscriptions
GET /api/v1/merchant/recurring/invoices
GET /api/v1/merchant/recurring/auditCreate a payoutBank card in RUB and USDT on TRON
Payout method
Bank card in RUB and USDT on TRON
Payout to a bank card
Transfer RUB by card number. Creation requires the recipient phone and name; use the payout status as the final result.
Sends amount, unique order number and beneficiary details.
Payout and fee are reserved. Reusing merchant_order_id does not create a duplicate.
Initial pending means the request is accepted but not final.
completed finalizes the reserve; failed releases the full reserved amount.
failed → released
Webhook
API requests and incoming webhooks use the same formula, but select keys differently. Notifications are signed with the project’s primary key pair, even when an additional API key created the payment.
- Read the original request body before JSON.parse. Do not alter key order, whitespace or Unicode before signature verification.
- Match X-API-KEY against the project’s primary public_key. Compute HMAC using the primary secret_key and the header’s X-TIMESTAMP.
- Compare signatures with a timing-safe comparison. After verification, persist X-Event-ID and process the event once.
- Return HTTP 2xx after durably storing the event. Return 2xx for repeated X-Event-ID without fulfilling the order twice.
body = raw_request_body_utf8
timestamp = header["X-TIMESTAMP"]
message = body + ":" + timestamp + "++"
signature = hex(hmac_sha256(base64(primary_secret_key), message))
X-API-KEY: <primary_public_key>
X-TIMESTAMP: <unix_seconds>
X-SIGNATURE: <signature>
X-Event-ID: <event_id>POST to the order’s callback_url or the project webhook.
Primary key pair + original body + X-TIMESTAMP.
X-Event-ID prevents duplicate processing. completed confirms payment.
A lost reply can cause redelivery of the same event, not a new payment.
Operations
This section contains read-only operations. Payment and payout creation is documented under each method above.
Payments
Retrieve one operation, a filtered list or an XLSX export.
GET /api/v1/merchant/transactions/{transaction_id}
GET /api/v1/merchant/transactions?page_number=1&items_per_page=50&status=completed
GET /api/v1/merchant/transactions/export?status=completedPayouts
Retrieve one payout by local or external ID, or a list filtered by status.
GET /api/v1/merchant/payouts/{payout_id}
GET /api/v1/merchant/payouts?page_number=1&items_per_page=50
GET /api/v1/merchant/payouts?page_number=1&items_per_page=50&status=pendingBalance and time
Check available and reserved balances or synchronize the signature timestamp.
GET /api/v1/merchant/balance GET /api/v1/merchant/timestamp
Before going live
Check both directions of communication before accepting live traffic.
- The test request is signed on the backend; the key is absent from browser code and your repository.
- Orders are confirmed by completed, not redirect_url_success.
- Receiving the same webhook twice does not deliver goods or update your balance twice.
- After a timeout, check the existing operation before creating another order.
- Handle declines, expiry and 3DS; check the interface on a phone.
When a request fails
401- Check the key pair, backend outgoing IP, Unix seconds and signed body. GET /timestamp also requires authentication.
422- Check names and formats against the selected method. Do not copy settings from a different flow.
409 / timeout- Find the existing operation by your order number. Do not charge again until its result is known.