Payout API#

Payouts authenticate differently from the rest of the API: instead of the X-MerchantId/X-Secret header pair, every request is signed with HMAC-SHA256 under a secret issued separately in the dashboard. That secret is shown once and Platega cannot recover it.

The functionality is disabled by default on a Platega account and enabled on request.

from aioplatega import PayoutClient

async with PayoutClient(merchant_id="...", secret="...") as payouts:
    cards = await payouts.get_cards()
    result = await payouts.create_card_payout(
        card_id=cards[0].card_id,
        amount_rub=1500,
    )
    print(result.status, result.amount_usdt_debited)

Note

Pass your own idempotency_key when a retry has to be safe. Without one a fresh key is generated per call, so a retried request would be treated as a second payout.

PayoutClient#

Client for the Payout API, which authenticates with PG-HMAC.

Kept separate from Platega on purpose: the two share a host but nothing else. Payouts are signed with a secret the merchant holds alone, every write is idempotency-keyed, and the signed bytes have to reach the socket unchanged — none of which the header-pair auth needs.

Payouts are off by default on a Platega account and enabled on request.

class aioplatega.payout.client.PayoutClient[source]#

Bases: object

Async client for the Platega Payout API.

Example

async with PayoutClient(merchant_id="...", secret="...") as payouts:
    cards = await payouts.get_cards()
    result = await payouts.create_card_payout(
        card_id=cards[0].card_id,
        amount_rub=1500,
    )
__init__(merchant_id, secret, api_url='https://app.platega.io')[source]#

Initialize the Payout client.

Parameters:
  • merchant_id (str) – Your Platega merchant identifier, sent as kid.

  • secret (str) – The Payout API secret. This is not the X-Secret used by Platega; it is issued separately, shown once, and Platega cannot recover it.

  • api_url (str) – Override the API base URL.

Return type:

None

async get_cards(*, only_active=True)[source]#

List the merchant’s saved payout cards.

Parameters:

only_active (bool) – When False, also returns DISABLED and PENDING cards.

Return type:

SavedCardsResponse

Returns:

An iterable of SavedCard.

async create_card_payout(*, amount_rub, card_id=None, card_number=None, idempotency_key=None)[source]#

Pay out to a RUB card.

Parameters:
  • amount_rub (int) – Amount in whole roubles, between 1000 and 87500.

  • card_id (str | None) – A saved card’s id. Mutually exclusive with card_number.

  • card_number (str | None) – A full 16-digit PAN. Mutually exclusive with card_id.

  • idempotency_key (str | None) – Reuse-protection key. Generated per call if omitted — pass your own to make a retry safe.

Return type:

CardPayoutResponse

Returns:

The created payout, with status CREATED.

Raises:

ValueError – If the card arguments or the amount are unusable. Checked here rather than at the API, because a payout that gets sent twice cannot be taken back.

async close()[source]#

Close the underlying HTTP session.

Return type:

None

Signing#

PG-HMAC request signing for the Payout API.

The Payout API does not use the X-MerchantId/X-Secret pair the rest of the API uses. Every request carries an HMAC-SHA256 signature over a canonical string, and the server only accepts timestamps within a +/-300 second window.

aioplatega.payout.signing.EMPTY_BODY_SHA256: Final[str] = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'#

SHA-256 of an empty body, used for GET requests.

aioplatega.payout.signing.TIMESTAMP_WINDOW_SECONDS: Final[int] = 300#

How far the server tolerates the client’s clock being off.

aioplatega.payout.signing.serialize_body(body)[source]#

Serialize a request body to the exact bytes that get signed.

Parameters:

body (dict[str, Any] | None) – The body to serialize, or None for a bodiless request.

Return type:

bytes

Returns:

Compact UTF-8 JSON, or empty bytes when there is no body.

Note

The separators matter. The signature covers these bytes, so the same buffer has to reach the socket; re-encoding the dict at send time could introduce whitespace and invalidate the signature.

aioplatega.payout.signing.build_string_to_sign(method, path, timestamp, idempotency_key, body)[source]#

Assemble the canonical string that gets signed.

Parameters:
  • method (str) – HTTP verb, upper-cased into the string.

  • path (str) – Request path, without the host or query string.

  • timestamp (int) – Unix time in seconds. The server accepts a window of +/-300 seconds around its own clock.

  • idempotency_key (str) – Reuse-protection key. Empty for reads, which still contribute an empty line to the string.

  • body (bytes) – The exact bytes of the request body.

Return type:

str

Returns:

The five elements joined by newlines.

aioplatega.payout.signing.sign(secret, string_to_sign)[source]#

Sign a canonical string.

Parameters:
Return type:

str

Returns:

Base64 of HMAC-SHA256(secret, string_to_sign).

aioplatega.payout.signing.authorization_header(merchant_id, timestamp, signature)[source]#

Render the Authorization header value.

Parameters:
  • merchant_id (str) – Merchant identifier, sent as kid.

  • timestamp (int) – The same timestamp that went into the signature.

  • signature (str) – Output of sign().

Return type:

str

Returns:

A PG-HMAC kid=..., ts=..., sig=... header value.