Developer-референс

Peptide-Pay API

REST API для приёма карт и крипты с расчётом в USDC на ваш кошелёк. Один POST создаёт checkout. Один вебхук сообщает об оплате. Запуск меньше чем за 30 минут.

REST · JSONBearer authHMAC-SHA256 вебхукиIdempotency-KeyCORS включён

С чего начать

Peptide-Pay поддерживает четыре режима интеграции. Выбирайте под свои ограничения — API под капотом одинаковый.

С чего начатьpick your stackShopify·WooCommerce·AI builders·Direct API
Подсказка
Новичок? Начинайте с Режима 2 (API-ключ) — откроется sandbox-кредит, метрики в дашборде и безопасность «кошелька не видно в DevTools». Получите ключ на /signup (бесплатно, ~30с).

Быстрый старт (5 мин)

Три шага: создать сессию, редиректнуть клиента, обработать вебхук. Пример ниже — готовый к проду Node.js checkout-роут.

app/checkout/route.ts
// Create a checkout session and redirect your customer.
// Authorization resolves the merchant wallet server-side — no wallet in the body.

const res = await fetch('https://peptide-pay.com/api/v1/checkout/init', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.PEPTIDEPAY_API_KEY}`, // sk_live_…
  },
  body: JSON.stringify({
    amount_cents: 5000,                       // €50.00 — integer, in cents
    currency: 'EUR',                          // EUR, USD, GBP, CAD, AUD, CHF
    email: 'buyer@example.com',               // optional, shown in checkout
    success_url: 'https://mystore.com/success',
    cancel_url:  'https://mystore.com/cart',
    webhook_url: 'https://mystore.com/api/peptidepay-webhook',
    metadata: { order_id: '1234' },
  }),
});

const { id, url, tracking_number } = await res.json();
// => { id: 'cs_abc…', url: 'https://peptide-pay.com/session/cs_abc…',
//      tracking_number: '0x…', provider: 'gateway', status: 'pending', … }

// Redirect your customer to the hosted checkout.
return Response.redirect(url, 303);

Это весь happy path. Клиент попадает на hosted checkout на , выбирает карту или крипту, а ваш вебхук срабатывает в течение 30с после оплаты.

Аутентификация

Две схемы — в зависимости от режима интеграции:

СхемаКакКогда
Bearer-токенAuthorization: Bearer sk_live_…Server-side. Кошелёк остаётся приватным.
Кошелёк в body{ "wallet": "0x…", … }Статические сайты / виджеты без backend.
Важно
API-ключи несут полную идентичность мерчанта — храните как пароли. Никогда не коммитьте, не шлите в браузер, ротируйте из /app/api-keys при утечке.
Подсказка
No sandbox mode. Signup returns both an sk_live_… and an sk_test_… key. Use sk_live_ as your canonical key — that is what every example here uses. The sk_test_ key is provided for the webhook-receiver simulator at /api/v1/test/fire-webhook. Peptide-Pay settles real on-chain USDC — there is no test network. To dry-run an integration, run a $1 real payment and refund yourself.

API-референс

Base URL: . Все эндпоинты говорят JSON, возвращают один объект на успех и на 4xx/5xx.

POSThttps://peptide-pay.com/api/v1/checkout/init

#Создать checkout-сессию

Создаёт URL hosted checkout. Клиент открывает, платит картой или криптой, Peptide-Pay рассчитывается вам в USDC, срабатывает вебхук.

Тело запроса
ПолеТипОбязательноОписание
amount_centsintegerобязательноСумма в наименьшей единице валюты (центы). Диапазон 100 – 10 000 000.
currencystringобязательноКод ISO 4217. Поддерживаются: EUR, USD, GBP, CAD, AUD, CHF.
walletstringone-ofUSDC-кошелёк на Polygon (0x + 40 hex). Обязательно, если не аутентифицированы через Bearer-ключ.
customer_emailstringопциональноПоказывается в UI checkout и прокидывается в on-ramp для переиспользования KYC.
success_urlurlопциональноРедирект после успешной оплаты. Только http/https.
cancel_urlurlопциональноРедирект, если клиент бросил checkout.
webhook_urlurlопциональноPOST-таргет для событий order.paid. Переопределяет дефолт из дашборда.
providerstringопциональноПо умолчанию 'gateway' (умный пикер — рекомендуется). Или зафиксируйте конкретный on-ramp id из GET /providers (например moonpay, revolut, banxa, transak).
product_namestringопциональноЛейбл на странице checkout (макс 80 символов).
metadataobjectопциональноДо 10 key/value-пар строк, возвращаются в вебхуке. Зарезервированный ключ: order_id.
Ответ (200 OK)
ПолеТипОбязательноОписание
idstringопциональноID сессии, начинается с cs_.
urlstringопциональноURL hosted checkout для редиректа клиента.
statusstringопциональноПри создании всегда "pending".
amountintegerопциональноEcho amount_cents.
currencystringопциональноEcho currency.
providerstringопциональноEcho provider (по умолчанию 'gateway').
expires_atstringопциональноISO 8601 срок жизни (24ч с создания).
tracking_numberstringопциональноPolygon settlement-адрес — совпадает с address_in в payload вебхука, пригоден для /track для live-мониторинга.

Примеры

// Node.js 18+
const res = await fetch('https://peptide-pay.com/api/v1/checkout/init', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.PEPTIDEPAY_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(),   // safe double-submit
  },
  body: JSON.stringify({
    amount_cents: 5000,
    currency: 'EUR',
    email: 'buyer@example.com',
    success_url: 'https://mystore.com/success',
    cancel_url:  'https://mystore.com/cart',
    metadata: { order_id: '1234' },
  }),
});

if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { id, url } = await res.json();
return Response.redirect(url, 303);
Подсказка
Передавайте , чтобы ретраи были безопасными. Мы переигрываем закешированный ответ 24ч по тому же ключу вместо создания новой сессии (защищает от двойных списаний на нестабильных сетях).
GEThttps://peptide-pay.com/api/v1/sessions/{id}

#Получить сессию (polling)

Используйте как fallback для вебхука или для гидратации success-страницы после редиректа. Каждый вызов server-side пере-проверяет наш settlement-слой — дёшево (<200мс), так что polling каждые 3-5с ок.

Ответ
ПолеТипОбязательноОписание
idstringопциональноID сессии.
statusstringопциональноpending | paid | expired | failed.
amountintegerопциональноИсходная сумма в центах.
currencystringопциональноИсходная валюта.
paid_atstring|nullопциональноISO 8601, когда on-chain settlement завершился.
paid_providerstring|nullопциональноКакой провайдер реально обработал платёж (может отличаться от запрошенного).
txidstring|nullопциональноTxid Polygon settlement. Линк через polygonscan.com/tx/{txid}.
expires_atstringопциональноISO 8601 срок жизни.
// Poll every 3-5 seconds until terminal state. Use webhooks for push-
// delivery in production; polling is the fallback when webhooks are down.
async function waitForPayment(sessionId, { timeoutMs = 15 * 60 * 1000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const res = await fetch(`https://peptide-pay.com/api/v1/sessions/${sessionId}`);
    const s = await res.json();
    if (s.status === 'paid')    return s;       // terminal: success
    if (s.status === 'expired') throw new Error('Session expired');
    if (s.status === 'failed')  throw new Error('Payment failed');
    await new Promise(r => setTimeout(r, 4000));
  }
  throw new Error('Polling timeout');
}
GEThttps://peptide-pay.com/api/v1/providers

#Live-матрица провайдеров

Список on-ramp'ов, принимающих трафик, с per-provider минимальными суммами. Кешируется 5 мин на edge — опрашивайте один раз при старте приложения, не на каждый запрос.

Ответ
ПолеТипОбязательноОписание
providers[].idstringопциональноКлюч провайдера (можно передавать как `provider` в /checkout/init).
providers[].provider_namestringопциональноЧеловекочитаемый лейбл для выпадашки.
providers[].statusstringопционально'active' (на этом эндпоинте всегда фильтр на active).
providers[].minimum_currencystringопциональноISO-код минимальной валюты.
providers[].minimum_amountnumberопциональноМинимальная сумма, которую принимает провайдер (в единицах minimum_currency).
curl -sS 'https://peptide-pay.com/api/v1/providers' | jq '.providers[] | {id, provider_name, minimum_currency, minimum_amount}'

# [
#   { "id": "gateway",  "provider_name": "Smart (recommended)",   "minimum_currency": "USD", "minimum_amount": 1 },
#   { "id": "moonpay",  "provider_name": "Moonpay",               "minimum_currency": "EUR", "minimum_amount": 20 },
#   { "id": "revolut",  "provider_name": "Revolut Ramp",          "minimum_currency": "EUR", "minimum_amount": 10 },
#   { "id": "binance",  "provider_name": "Binance Pay",           "minimum_currency": "EUR", "minimum_amount": 15 },
#   …
# ]
# Cache: 5 minutes at the edge. Call once per deploy, not per request.

Вебхуки

Когда сессия достигает терминального состояния, мы шлём POST с подписанным JSON-событием на , который вы настроили (per-session или в дашборде). Всегда парсите -тело запроса для верификации подписи — пере-сериализация JSON переупорядочивает ключи и ломает HMAC.

POST /your-endpoint  HTTP/1.1
Host: mystore.com
Content-Type: application/json
x-peptidepay-signature: t=1745300551,v1=3f9b5c1e8a7d…    ← HMAC-SHA256, hex

{
  "event":      "order.paid",
  "session_id": "cs_abc123",
  "order_id":   "1234",
  "address_in": "0xAb12…",
  "status":     "paid",
  "amount":     5000,
  "currency":   "EUR",
  "txid":       "0xfa89b2…",
  "paid_at":    "2026-04-23T10:02:31.000Z",
  "attempt":    1
}

Типы событий

СобытиеКогда
order.paidПодтверждён on-chain settlement. + + гарантированно присутствуют. Помечайте заказ оплаченным.

Сейчас доставляется только — expired и failed сессии наблюдаемы через (status уходит в после 24ч TTL; терминальные сбои — ). Возможно, добавим push-события для них в будущем.

Верификация подписи

Мерчанты со signup-аккаунтом получают секрет , и каждая доставка несёт заголовок вида . Считайте и сравнивайте с constant-time. Отбрасывайте всё старше 5 минут.

Подсказка
Wallet-only flow'ы (без регистрации, без ) доставляют вебхук без подписи — всё равно валидируйте, что соответствует созданной вами сессии. Для подписанных доставок регистрируйтесь на /signup и получайте секрет.
// Node.js — Express/Next.js route handler
import crypto from 'node:crypto';

const SECRET = process.env.PEPTIDEPAY_WEBHOOK_SECRET; // dashboard → Webhooks

export async function POST(req) {
  const rawBody = await req.text();                 // MUST be the raw bytes
  const header  = req.headers.get('x-peptidepay-signature') ?? '';
  const [ tPart, v1Part ] = header.split(',');
  const t  = tPart?.split('=')[1];
  const v1 = v1Part?.split('=')[1];
  if (!t || !v1) return new Response('bad sig', { status: 400 });

  // Reject replays older than 5 minutes.
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300)
    return new Response('stale', { status: 400 });

  const expected = crypto
    .createHmac('sha256', SECRET)
    .update(`${t}.${rawBody}`)
    .digest('hex');

  const ok =
    v1.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(v1, 'hex'), Buffer.from(expected, 'hex'));
  if (!ok) return new Response('invalid sig', { status: 401 });

  const event = JSON.parse(rawBody);
  // Idempotency: dedupe by event.session_id in your DB — retries re-fire
  // the same event (with an incrementing "attempt" field) until you 2xx.
  if (event.event === 'order.paid') {
    await markOrderPaid(event.order_id, event.txid);
  }
  return new Response('ok');
}
Важно
Всегда используйте constant-time compare для вашего языка: (Node), (Python), (PHP), (Ruby). Обычный утекает HMAC по байту timing-атакующему.

Политика повторов

Ретраим non-2xx ответы (и таймауты > 5с) на экспоненциальном backoff. Шесть попыток за ~42 часа:

  • Попытка 1 — сразу при подтверждении.
  • Попытка 2 — +5 минут.
  • Попытка 3 — +15 минут.
  • Попытка 4 — +1 час.
  • Попытка 5 — +4 часа.
  • Попытка 6 — +12 часов, затем +24 часа (финал).

После 6 неудачных попыток событие уходит в dead-letter. Текущее состояние всегда можно перезапросить через .

Подсказка
Делайте ваш хендлер идемпотентным. Дедупайте по — ретрай может ещё раз стрельнуть paid-событием, которое вы уже обработали.

Частые проблемы

На каждой доставке вижу 'invalid signature'
Ваш фреймворк распарсил тело как JSON до того, как вы его захешировали. Читайте RAW-байты (Express: express.raw({type:'*/*'}); Next.js: req.text(); Laravel: request()->getContent(); Rails: request.raw_post). Никогда не пере-сериализуйте перед хешированием.
IP whitelist — с каких IP вы шлёте?
Доставки сейчас идут с Vercel Edge (динамические IP). Мы не публикуем статический диапазон. Если ОБЯЗАНЫ заwhitelist'ить — используйте заголовок подписи как auth-gate и принимайте любой source IP; HMAC — это и есть настоящая проверка идентичности.
HTTPS обязателен?
Да. Отказываемся POST'ить на http:// эндпоинты (risk confusable deputy / plaintext replay). Бесплатный https URL от ngrok ок для локального тестирования.
Мой эндпоинт медленный — можно увеличить таймаут 5с?
Нет. Отвечайте 2xx сразу, а обрабатывайте асинхронно (очередь, setImmediate, goroutine). Долгие блокирующие хендлеры всегда заканчиваются таймаутом.

SDK

API достаточно маленький, чтобы хватило с головой — но Node SDK даёт типы, автоматические ретраи и хелпер , который делает верификацию подписи за вас.

npm install github:kinerette/peptide-pay-sdk
// npm install github:kinerette/peptide-pay-sdk

import { PeptidePay } from 'peptide-pay';

const pp = new PeptidePay(process.env.PEPTIDEPAY_API_KEY);

// Create a session
const session = await pp.checkout.create({
  amount_cents: 5000,
  currency: 'EUR',
  customer_email: 'buyer@example.com',
  success_url: 'https://mystore.com/success',
  cancel_url:  'https://mystore.com/cart',
  metadata: { order_id: '1234' },
});

// Retrieve a session
const latest = await pp.sessions.retrieve(session.id);

// Verify + parse a webhook (throws on invalid signature)
app.post('/webhooks/peptidepay', express.raw({ type: '*/*' }), (req, res) => {
  const event = pp.webhooks.constructEvent(
    req.body,
    req.headers['x-peptidepay-signature'],
    process.env.PEPTIDEPAY_WEBHOOK_SECRET,
  );
  // event.event === 'order.paid' (currently the only event delivered)
  res.sendStatus(200);
});
Node / TypeScriptstable
peptide-pay

Полные типы, webhook-хелпер, автоматические ретраи.

Прямой fetch()работает всегда
любой язык

Один POST, один GET. Библиотеки не нужны.

Подсказка
SDK для Python, PHP, Ruby и Go в roadmap. Пока не вышли — голые примеры // выше остаются каноническим референсом — мы их не сломаем.

Комиссии

Flat — полная комиссия Peptide-Pay. Без подписки, без абонплаты, без chargeback-комиссий. Комиссии карт on-ramp (~4.5%, берёт upstream card-процессор) — pass-through, их платит клиент, они не трогают вашу выплату.

Способ оплатыВы платитеПлатит клиент
Карта / Apple Pay / Google Pay3%~4.5% (on-ramp, pass-through)
Крипта напрямую (USDC → USDC)3%только gas (~$0.01 на Polygon)

Полный разбор с примерами на /fees.

Тестирование

Каждый новый мерчант-аккаунт получает бесплатно — полные 3% возвращаются вам на кошелёк в течение 24ч. Прогоняйте полный flow end-to-end (реальная карта, реальный USDC, реальный вебхук) до запуска в прод.

  • Sandbox-режим автоматический: первые 3 оплаченных сессии на мерчанта помечаются и идут на auto-refund.
  • Тестовая карта MoonPay: , любая будущая дата, любой CVV, ZIP 10001.
  • Локальное тестирование вебхука: проброс localhost через ngrok, вставьте URL в поле на сессии.

Полный локальный loop (ngrok)

# 1. Expose your local webhook endpoint
ngrok http 3000

# 2. Copy the https://xxxx.ngrok-free.app URL and paste it into
#    Dashboard → Webhooks → Endpoint URL, OR send it inline:
curl -X POST 'https://peptide-pay.com/api/v1/checkout/init' \
  -H "Authorization: Bearer $PEPTIDEPAY_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "amount_cents": 100,
    "currency": "EUR",
    "customer_email": "test+sandbox@yours.com",
    "success_url": "https://yours.com/success",
    "cancel_url":  "https://yours.com/cart",
    "webhook_url": "https://xxxx.ngrok-free.app/webhooks/peptidepay"
  }'

# 3. Open the returned `url`, hit MoonPay's dev test card
#    4242 4242 4242 4242 (any future exp, any CVV).
# 4. Your local endpoint receives the signed POST within ~30s of payment.

Ошибки и rate limits

Все ошибки — единой формы . Статус-коды стандартные REST.

400
Невалидный JSON или отсутствует поле
Тело битое, amount не число, wallet не 0x-адрес, валюта не поддерживается.
401
Невалидный или отозванный API-ключ
Bearer-токен не разрешается в мерчанта. Ротируйте в /app/api-keys.
403
Плохая подпись callback
Внутренняя — наш settlement IPN попал в webhook-приёмник без корректной per-session подписи. В нормальной работе не видна мерчанту.
404
Сессия не найдена
Неверный id или сессия подчищена (> 90д после терминального состояния).
429
Превышен rate limit
60 req/min/IP на init, 30 req/min/IP на select. Заголовок Retry-After включён. Для higher tier пишите в саппорт.
502
Upstream недоступен
Settlement-сеть временно деградировала. Ретрайте через 30с с тем же Idempotency-Key. Целевой SLA: 99.5%+.

Troubleshooting

Сессия 'paid' в дашборде, но мой вебхук так и не стрельнул
Проверьте, что webhook_url доступен по публичному HTTPS (curl'ните из-за LAN). Если ок — опросите GET /sessions/{id} для подтверждения статуса; дашборд /app показывает статистику доставки (success rate, счётчики). Шесть попыток за 42ч до dead-letter; всегда можно ре-синкнуть через polling.
HMAC mismatch — подпись всегда невалидна
99% случаев: вы хешируете пере-сериализованное тело вместо raw-байтов. Фреймворки автопарсят JSON до хендлера; нужен сырой буфер. Next.js: req.text() до любого .json(). Express: app.use('/webhooks', express.raw({ type: '*/*' }), …). Rails: request.raw_post. Также проверьте, что считаете `HMAC(whsec_secret, t + '.' + rawBody)` — НЕ просто `HMAC(whsec_secret, rawBody)`. Префикс таймстемпа обязателен.
MoonPay говорит 'service unavailable in your country'
MoonPay ограничивает ~20 стран (Иран, Северная Корея, Куба, полный список на их сайте). Дефолтный провайдер — 'gateway', умный пикер авто-откатывается на Revolut, Transak или Banxa с другой гео-покрытием. Если зафиксировали конкретного провайдера через provider: 'moonpay' — уберите и дайте роутеру выбирать.
Кошелёк не получил USDC после 'paid'-события
Смотрите polygonscan.com/address/<your-wallet> на USDC (Polygon POS) переводы. Settlement уходит 97% вам и 3% Peptide-Pay — если не видите входящие 97%, возможно, вставили не тот кошелёк в init-вызов. Подтвердите через GET /sessions/{id} — поле txid указывает на реальный on-chain перевод.
Клиента списали дважды
Не должно происходить. У каждой сессии один settlement addressIn; второй платёж на тот же адрес станет отдельной сессией у нас, и только первую мы зачислим в ваш заказ. Если случилось — скриньте оба polygonscan-txid + session id и пишите на hi@peptide-pay.com — вернём дубль из treasury.
Получаю 502 'Payment infrastructure temporarily unavailable'
Наш settlement-upstream деградировал (< 0.5% запросов). Ретрайте через 30с с тем же Idempotency-Key — кеш вернёт исходный ответ, как только кошелёк успешно создастся. Следите за /status за live-инцидентами.

Готовы интегрироваться?

Большинство мерчантов проходят путь от нуля до первой оплаченной транзакции меньше чем за 30 минут.