Перейти к содержимому
API-документация

Быстрый старт

От ключа до первой карты — пять запросов с примерами.

Понадобятся ключ API (идентификатор и секрет) и curl, openssl, uuidgen в терминале. Примеры на Node.js, Python и PHP используют функцию pp() из раздела Аутентификация и подпись — скопируйте её в проект.

Начните с тестового ключа

Ключ pp_test_… работает с тестовым аккаунтом: карты не настоящие, баланс виртуальный, остальное поведение — как у боевого. Запросите его у менеджера вместе с боевым.

0. Ключ в переменных окружения

export PP_KEY_ID="pp_test_9f2c1a7e"
export PP_SECRET="ваш-секрет"

Секрет храните как пароль: в менеджере секретов, не в репозитории. Его показывают один раз при выпуске ключа.

1. Проверьте баланс

Самый простой подписанный запрос: GET без тела.

TS=$(date +%s)
SIG=$(printf '%s\n%s\n%s\n%s' "$TS" "GET" "/api/partner/v1/balance" "" \
  | openssl dgst -sha256 -hmac "$PP_SECRET" -hex | awk '{print $NF}')

curl -sS "https://api.plativputi.com/api/partner/v1/balance" \
  -H "X-Key-Id: $PP_KEY_ID" -H "X-Timestamp: $TS" -H "X-Signature: $SIG"
const balance = await pp("GET", "/balance");
balance = pp("GET", "/balance")
$balance = pp('GET', '/balance');
{ "currency": "USD", "balance": "1250.5", "hold": "0", "available": "1250.5" }

Если пришёл 401 — проверьте часы сервера (окно ±5 минут) и строку подписи, см. частые ошибки подписи.

2. Выберите тариф

TS=$(date +%s)
SIG=$(printf '%s\n%s\n%s\n%s' "$TS" "GET" "/api/partner/v1/tariffs" "" \
  | openssl dgst -sha256 -hmac "$PP_SECRET" -hex | awk '{print $NF}')

curl -sS "https://api.plativputi.com/api/partner/v1/tariffs" \
  -H "X-Key-Id: $PP_KEY_ID" -H "X-Timestamp: $TS" -H "X-Signature: $SIG"
const { items } = await pp("GET", "/tariffs");
const tariffId = items[0].id;
tariff_id = pp("GET", "/tariffs")["items"][0]["id"]
$tariffId = pp('GET', '/tariffs')['items'][0]['id'];
{
  "items": [
    {
      "id": "3f6c2a1e-8b4d-4e2a-9c71-5d0e8f1a2b34",
      "name": "Visa Virtual USD",
      "issue_fee": "5",
      "close_fee": "1",
      "close_refund_fee_pct": "0",
      "topup_fee_pct": "3",
      "topup_fee_const": "0.5",
      "tx_fee_ok": "0.2",
      "tx_fee_declined": "0.5",
      "min_topup": "10",
      "max_topup": "5000"
    }
  ]
}

Как из этих полей складывается цена — в разделе Деньги.

3. Зарегистрируйте держателя

external_id — ваш идентификатор клиента. Используйте один и тот же для всех карт одного человека: первая карта нового держателя ждёт проверки личности у эмитента, следующие — нет.

BODY='{"external_id":"cust-42","first_name":"Ivan","last_name":"Petrov","email":"ivan.petrov@example.com"}'
TS=$(date +%s)
SIG=$(printf '%s\n%s\n%s\n%s' "$TS" "POST" "/api/partner/v1/cardholders" "$BODY" \
  | openssl dgst -sha256 -hmac "$PP_SECRET" -hex | awk '{print $NF}')

curl -sS -X POST "https://api.plativputi.com/api/partner/v1/cardholders" \
  -H "X-Key-Id: $PP_KEY_ID" -H "X-Timestamp: $TS" -H "X-Signature: $SIG" \
  -H "Content-Type: application/json" -d "$BODY"
const holder = await pp("POST", "/cardholders", {
  external_id: "cust-42",
  first_name: "Ivan",
  last_name: "Petrov",
  email: "ivan.petrov@example.com",
});
holder = pp("POST", "/cardholders", body={
    "external_id": "cust-42",
    "first_name": "Ivan",
    "last_name": "Petrov",
    "email": "ivan.petrov@example.com",
})
$holder = pp('POST', '/cardholders', [
    'external_id' => 'cust-42',
    'first_name' => 'Ivan',
    'last_name' => 'Petrov',
    'email' => 'ivan.petrov@example.com',
]);
{
  "id": "b7e1c9d2-4a3f-4c8e-a6b5-1f2e3d4c5b6a",
  "external_id": "cust-42",
  "first_name": "Ivan",
  "last_name": "Petrov",
  "email": "ivan.petrov@example.com",
  "created_at": "2026-10-07T09:12:44Z"
}

Имя и фамилия — латиницей, как они будут на карте. Повторный вызов с тем же external_id вернёт этого же держателя.

4. Выпустите карту

amount — сколько положить на карту сразу. Idempotency-Key обязателен: сгенерируйте его один раз и сохраните до отправки — при обрыве связи повторите запрос с тем же ключом.

BODY='{"tariff_id":"3f6c2a1e-8b4d-4e2a-9c71-5d0e8f1a2b34","holder_external_id":"cust-42","amount":"50"}'
IDEM=$(uuidgen)
TS=$(date +%s)
SIG=$(printf '%s\n%s\n%s\n%s\n%s' "$TS" "POST" "/api/partner/v1/cards" "$BODY" "$IDEM" \
  | openssl dgst -sha256 -hmac "$PP_SECRET" -hex | awk '{print $NF}')

curl -sS -X POST "https://api.plativputi.com/api/partner/v1/cards" \
  -H "X-Key-Id: $PP_KEY_ID" -H "X-Timestamp: $TS" -H "X-Signature: $SIG" \
  -H "Idempotency-Key: $IDEM" -H "Content-Type: application/json" -d "$BODY"
import { randomUUID } from "node:crypto";

const idempotencyKey = randomUUID(); // сохраните рядом с вашим заказом
const op = await pp("POST", "/cards", {
  tariff_id: tariffId,
  holder_external_id: "cust-42",
  amount: "50",
}, { idempotencyKey });
import uuid

idempotency_key = str(uuid.uuid4())  # сохраните рядом с вашим заказом
op = pp("POST", "/cards", body={
    "tariff_id": tariff_id,
    "holder_external_id": "cust-42",
    "amount": "50",
}, idempotency_key=idempotency_key)
$idempotencyKey = uuid4(); // сохраните рядом с вашим заказом
$op = pp('POST', '/cards', [
    'tariff_id' => $tariffId,
    'holder_external_id' => 'cust-42',
    'amount' => '50',
], $idempotencyKey);

Ответ 202 Accepted — операция, а не карта:

{
  "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
  "kind": "issue",
  "status": "processing",
  "hold_amount": "57.0464",
  "net_amount": "50",
  "created_at": "2026-10-07T09:13:02Z"
}

hold_amount зарезервирован на балансе: 5 USD выпуск + 50 USD на карту + 2.0464 USD комиссия пополнения.

5. Дождитесь результата

Опрашивайте операцию, пока status равен processing. В боевой интеграции вместо опроса подпишитесь на события.

OP=c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f
TS=$(date +%s)
SIG=$(printf '%s\n%s\n%s\n%s' "$TS" "GET" "/api/partner/v1/operations/$OP" "" \
  | openssl dgst -sha256 -hmac "$PP_SECRET" -hex | awk '{print $NF}')

curl -sS "https://api.plativputi.com/api/partner/v1/operations/$OP" \
  -H "X-Key-Id: $PP_KEY_ID" -H "X-Timestamp: $TS" -H "X-Signature: $SIG"
let current = op;
while (current.status === "processing") {
  await new Promise((r) => setTimeout(r, 3000));
  current = await pp("GET", `/operations/${op.id}`);
}
if (current.status !== "succeeded") throw new Error(current.error_code);
const card = await pp("GET", `/cards/${current.card_id}`);
import time

current = op
while current["status"] == "processing":
    time.sleep(3)
    current = pp("GET", f"/operations/{op['id']}")
if current["status"] != "succeeded":
    raise RuntimeError(current.get("error_code"))
card = pp("GET", f"/cards/{current['card_id']}")
$current = $op;
while ($current['status'] === 'processing') {
    sleep(3);
    $current = pp('GET', '/operations/' . $op['id']);
}
if ($current['status'] !== 'succeeded') {
    throw new RuntimeException($current['error_code'] ?? 'failed');
}
$card = pp('GET', '/cards/' . $current['card_id']);
{
  "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "state": "active",
  "holder_external_id": "cust-42",
  "masked_number": "**** **** **** 4821",
  "payment_system": "VISA",
  "currency": "USD",
  "balance": "50",
  "expires_at": "10/29",
  "created_at": "2026-10-07T09:13:02Z"
}

Карта готова. Что дальше: