Skip to documentation

Aeris API documentation

Reference for authentication, creating payments and payouts, webhook events and status checks.

Download Postman documentation

Main 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.
Payment flow
A regular SBP payment through the Aeris page: create → receive URL → open payment → verify the result.
Choose who controls payment

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.

Dashboard
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 domains

Authentication

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.

HMAC-SHA256 · API
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.

Payment page

SBP + SberPay

One payment page with the methods available to the customer. A payment is created after a method is selected.

When to useThe main checkout when the customer chooses the payment method.
Payment flow
Select a step to open its explanation and example.

Aeris payment page

Order 10001

Order payment

Demo Store

RUB 9,000

The result will appear on this page

Interface illustration. Demonstration data, not a live payment link.

    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.

    Payment flow
    Select a step to open its explanation and example.

    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.

    POST /api/v1/merchant/recurring/subscriptions/action
    {
      "subscription_id": "e5a0c035-bef2-48a5-b59b-035cbd877eaf",
      "expected_version": 2,
      "action": "pause"
    }
    HTTP 200 · application/json
    {
      "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
    POST /api/v1/merchant/payins/sbp
    # 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"
    HTTP 200 · application/json
    {
      "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.

    Recurring payment terms

    Request and code
    POST /api/v1/merchant/recurring/subscriptions
    # 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"
    HTTP 200 · application/json
    {
      "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.

    API
    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/audit
    Create a payoutBank card in RUB and USDT on TRON

    Payout method

    Bank card in RUB and USDT on TRON

    Bank card

    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.

    When to useRefunds, rewards and batch payouts to individuals in Russia.
    Payment flow
    Select a step to open its explanation and example.
    availablecreatedfrozencompleted → debited
    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.

    1. Read the original request body before JSON.parse. Do not alter key order, whitespace or Unicode before signature verification.
    2. Match X-API-KEY against the project’s primary public_key. Compute HMAC using the primary secret_key and the header’s X-TIMESTAMP.
    3. Compare signatures with a timing-safe comparison. After verification, persist X-Event-ID and process the event once.
    4. Return HTTP 2xx after durably storing the event. Return 2xx for repeated X-Event-ID without fulfilling the order twice.
    HMAC-SHA256 · webhook
    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>
    Payment flow
    The customer’s return and webhook delivery are independent. A verified webhook or status GET supplies the result.

    Operations

    This section contains read-only operations. Payment and payout creation is documented under each method above.

    PAYMENTS

    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=completed
    PAYOUTS

    Payouts

    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=pending
    PROJECT

    Balance 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.