Developer referansı

Peptide-Pay API

Kart ve kripto için REST API, kontrol ettiğin bir USDC wallet'a settlement. Bir POST checkout oluşturur. Bir webhook ödendiğini söyler. 30 dakikanın altında canlıya al.

REST · JSONBearer authHMAC-SHA256 webhook'larIdempotency-KeyCORS destekli

Başlarken

Quickstart (5 dk)

Üç adım: session oluştur, müşteriyi yönlendir, webhook'u işle. Aşağıdaki örnek production-ready Node.js checkout route'u.

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'in tamamı bu. Müşteri 'ta hosted checkout'a düşer, kart veya kripto seçer, webhook'un ödeme sonrası 30 saniye içinde tetiklenir.

Authentication

Entegrasyon moduna göre iki şema:

ŞemaNasılNe zaman
Bearer tokenAuthorization: Bearer sk_live_…Server-side. Wallet'ı gizli tutar.
Body'de wallet{ "wallet": "0x…", … }Backend'siz static site / widget'lar.
Dikkat
API key'ler merchant hesabının tam kimliğini taşır — parolaymış gibi davran. Asla commit etme, asla browser'a gönderme, sızdıysa şuradan rotate et: /app/api-keys.
İpucu
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 referansı

Base URL: . Tüm endpoint'ler JSON konuşur, başarıda tek object döner, 4xx/5xx'te object döner.

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

#Checkout session oluştur

Hosted checkout URL üretir. Müşteri açar, kart veya kripto ile öder, Peptide-Pay wallet'ına USDC olarak settle eder, webhook tetiklenir.

Request body
AlanTürZorunluAçıklama
amount_centsintegerzorunluEn küçük para birimi cinsinden tutar (cent). Aralık 100 – 10 000 000.
currencystringzorunluISO 4217 kodu. Desteklenen: EUR, USD, GBP, CAD, AUD, CHF.
walletstringone-ofPolygon'da USDC wallet (0x + 40 hex). Bearer key ile kimlik doğrulanmadıysa zorunlu.
customer_emailstringopsiyonelCheckout UI'da gösterilir ve KYC yeniden kullanımı için on-ramp'a iletilir.
success_urlurlopsiyonelBaşarılı ödeme sonrası redirect. Sadece http/https.
cancel_urlurlopsiyonelMüşteri checkout'u terk ederse redirect.
webhook_urlurlopsiyonelorder.paid event'leri için POST hedefi. Dashboard default'unu override eder.
providerstringopsiyonelDefault 'gateway' (akıllı seçici — önerilen). Veya GET /providers'tan belirli bir on-ramp id'yi sabitle (ör. moonpay, revolut, banxa, transak).
product_namestringopsiyonelCheckout sayfasında gösterilen etiket (maks 80 karakter).
metadataobjectopsiyonelEn fazla 10 string key/value çifti, webhook'ta geri döner. Rezerve key: order_id.
Response (200 OK)
AlanTürZorunluAçıklama
idstringopsiyonelSession id, cs_ ile başlar.
urlstringopsiyonelMüşteriyi yönlendirilecek hosted checkout URL.
statusstringopsiyonelOluşturmada her zaman "pending".
amountintegeropsiyonelamount_cents yankısı.
currencystringopsiyonelcurrency yankısı.
providerstringopsiyonelprovider yankısı (default 'gateway').
expires_atstringopsiyonelISO 8601 expiry (oluşturmadan 24 saat).
tracking_numberstringopsiyonelPolygon settlement adresi — webhook payload'undaki address_in ile eşleşir, canlı takip için /track ile kullanılır.

Örnekler

// 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);
İpucu
Retry'ları güvenli yapmak için 'u gönder. Aynı key'de yeni session oluşturmak yerine 24 saat boyunca cache'lenmiş response'u replay ederiz (flaky network'te çift tahsilat önler).
GEThttps://peptide-pay.com/api/v1/sessions/{id}

#Session al (polling)

Bunu webhook fallback olarak veya redirect sonrası success sayfasını hydrate etmek için kullan. Server-side her çağrıda settlement katmanımızı yeniden kontrol eder — ucuz (<200ms), 3-5sn'de bir poll gayet iyi.

Response
AlanTürZorunluAçıklama
idstringopsiyonelSession id.
statusstringopsiyonelpending | paid | expired | failed.
amountintegeropsiyonelOrijinal tutar, cent olarak.
currencystringopsiyonelOrijinal para birimi.
paid_atstring|nullopsiyonelOn-chain settlement tamamlandığında ISO 8601.
paid_providerstring|nullopsiyonelÖdemeyi gerçekten işleyen provider (istenenden farklı olabilir).
txidstring|nullopsiyonelPolygon settlement txid. polygonscan.com/tx/{txid} ile linkle.
expires_atstringopsiyonelISO 8601 expiry.
// 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

#Canlı provider matrisi

Şu anda trafik kabul eden on-ramp'ları, provider başına minimum tutarla listeler. Edge'de 5 dk cache'li — app boot'ta bir kez poll et, her request'te değil.

Response
AlanTürZorunluAçıklama
providers[].idstringopsiyonelProvider key (/checkout/init'te `provider` olarak geçilebilir).
providers[].provider_namestringopsiyonelDropdown için insan okunur etiket.
providers[].statusstringopsiyonel'active' (bu endpoint'te her zaman active filtrelenir).
providers[].minimum_currencystringopsiyonelMinimum'un ISO kodu.
providers[].minimum_amountnumberopsiyonelProvider'ın kabul ettiği en düşük tutar (minimum_currency biriminde).
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.

Webhook'lar

Bir session terminal state'e ulaştığında yapılandırdığın 'e (session başına veya dashboard'da) imzalı bir JSON event POST ederiz. İmza doğrulama için her zaman request body'yi parse et — JSON'u yeniden serialize etmek key sırasını bozar ve HMAC kırılır.

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
}

Event türleri

EventNe zaman
order.paidOn-chain settlement onaylandı. + + garanti mevcut. Siparişi ödendi işaretle.

Bugün sadece teslim ediliyor — expired ve failed session'lar ile gözlemlenebilir (24 saat TTL sonrası status olur; terminal failure'lar gösterir). İleride bunlar için push event ekleyebiliriz.

İmza doğrulama

Signup hesabı olan merchant'lar bir secret alır ve her teslimat formunda header taşır. hesapla ve ile constant-time karşılaştır. 5 dakikadan eskisini reddet.

İpucu
Wallet-only akışları (signup yok, yok) webhook'u imzasız teslim eder — yine de 'in oluşturduğun bir session'la eşleştiğini doğrulamalısın. İmzalı teslimat için şuradan kaydol /signup secret'ını al.
// 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');
}
Dikkat
Her zaman constant-time karşılaştırma kullan, dilin için: (Node), (Python), (PHP), (Ruby). Düz bir HMAC'i timing attacker'a byte byte sızdırır.

Retry politikası

Non-2xx response'ları (ve >5sn timeout'ları) exponential backoff ile tekrar deneriz. ~42 saatte toplam altı deneme:

  • Deneme 1 — onaydan hemen sonra.
  • Deneme 2 — +5 dakika.
  • Deneme 3 — +15 dakika.
  • Deneme 4 — +1 saat.
  • Deneme 5 — +4 saat.
  • Deneme 6 — +12 saat, sonra +24 saat (son).

6 başarısız denemeden sonra event dead-letter olur. Mevcut state'i istediğin zaman ile yeniden talep edebilirsin.

İpucu
Handler'ını idempotent yap. üzerinde dedupe et — retry daha önce işlediğin bir paid event'i tekrar tetikleyebilir.

Sık karşılaşılan sorunlar

Her teslimatta 'invalid signature' görüyorum
Framework'ün hash'lemeden önce body'yi JSON parse etti. RAW byte'ları oku (Express: express.raw({type:'*/*'}); Next.js: req.text(); Laravel: request()->getContent(); Rails: request.raw_post). Hash'lemeden önce asla yeniden serialize etme.
IP whitelist — hangi IP'lerden gönderiyorsunuz?
Teslimatlar şu anda Vercel Edge'den (dinamik IP'ler) geliyor. Statik aralık yayınlamıyoruz. MUTLAKA whitelist yapman gerekiyorsa, imza header'ını auth gate olarak kullan ve herhangi bir source IP'yi kabul et — HMAC gerçek kimlik kontrolü.
HTTPS zorunlu mu?
Evet. http:// endpoint'lere POST yapmayı reddederiz (confusable deputy / plaintext replay riski). ngrok'un ücretsiz https URL'i local test için gayet iyi.
Endpoint'im yavaş — 5sn timeout'u uzatabilir miyim?
Hayır. Hemen 2xx cevapla, sonra asenkron işle (job queue, setImmediate, goroutine). Uzun bloklayan handler'lar her zaman timeout olur.

SDK'lar

API yeterince küçük, sadece gayet iyi — ama Node SDK sana type'ları, otomatik retry'ı ve imza doğrulamayı senin yerine yapan bir helper'ı veriyor.

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

Tam type'lar, webhook helper, otomatik retry.

Direkt fetch()her zaman çalışır
herhangi bir dil

Bir POST, bir GET. Library gerekmez.

İpucu
Python, PHP, Ruby ve Go SDK'ları roadmap'te. Onlar çıkana kadar yukarıdaki raw // örnekleri kanonik referans — onları bozmayacağız.

Komisyonlar

Sabit — Peptide-Pay'in tam komisyonu. Subscription yok, aylık yok, chargeback komisyonu yok. Kart on-ramp komisyonları (~%4.5, upstream kart processor'dan) pass-through — müşteri öder, senin payout'una dokunmaz.

Ödeme yöntemiSen ödersinMüşteri öder
Kart / Apple Pay / Google Pay%3~%4.5 (on-ramp, pass-through)
Direkt kripto (USDC → USDC)%3sadece gas (~$0.01 Polygon'da)

Çözümlü örneklerle tam breakdown: /fees.

Test

Her yeni merchant hesabı bedava alır — %3 komisyonun tamamı 24 saat içinde wallet'a iade edilir. Canlıya almadan önce uçtan uca akışı (gerçek kart, gerçek USDC, gerçek webhook) prova etmek için bunları kullan.

  • Sandbox mode otomatik: merchant başına ilk 3 ödenen session olarak işaretlenir ve auto-refund'a uygun olur.
  • MoonPay dev kartı: , herhangi bir gelecek expiry, herhangi bir CVV, ZIP 10001.
  • Local webhook testi: localhost'u ngrok ile expose et, URL'i her session'ın alanına yapıştır.

Tam local 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.

Hatalar & rate limit'ler

Tüm hatalar yapısını paylaşır. Status code'lar standart REST.

400
Geçersiz JSON veya eksik alan
Body bozuk, amount sayısal değil, wallet 0x adres değil, currency desteklenmiyor.
401
Geçersiz veya revoke edilmiş API key
Bearer token bir merchant'a çözülmüyor. /app/api-keys'ten rotate et.
403
Kötü callback imzası
İç — settlement IPN'imiz doğru session başına imza olmadan webhook receiver'a geldi. Normal operasyonda merchant'a yönelik bir hata değil.
404
Session bulunamadı
Yanlış id veya session budandı (terminal state'ten >90g sonra).
429
Rate limit aşıldı
init'te 60 req/dk/IP, select'te 30 req/dk/IP. Retry-After header dahil. Yüksek tier için destek ile iletişime geç.
502
Upstream erişilemez
Settlement network geçici bozuk. Aynı Idempotency-Key ile 30sn sonra tekrar dene. SLA hedefi: %99.5+.

Troubleshooting

Session dashboard'da 'paid' ama webhook'um hiç tetiklenmedi
webhook_url'inin public HTTPS üzerinden erişilebilir olduğunu kontrol et (LAN dışından curl at). Doğruysa, GET /sessions/{id} ile poll edip status'u onayla — dashboard /app webhook delivery istatistiklerini gösterir (başarı oranı, sayılar). Dead-letter'dan önce 42 saatte altı deneme; her zaman polling ile re-sync edebilirsin.
HMAC mismatch — imza her zaman geçersiz
%99 ihtimalle: raw byte'lar yerine yeniden serialize edilmiş body'yi hash'liyorsun. Framework'ler handler çalışmadan önce JSON'u otomatik parse eder; raw buffer'a ihtiyacın var. Next.js: herhangi bir .json()'dan önce req.text(). Express: app.use('/webhooks', express.raw({ type: '*/*' }), …). Rails: request.raw_post. Ayrıca `HMAC(whsec_secret, t + '.' + rawBody)` hesapladığını kontrol et — SADECE `HMAC(whsec_secret, rawBody)` DEĞİL. Timestamp prefix zorunlu.
MoonPay 'service unavailable in your country' diyor
MoonPay ~20 ülkeyi kısıtlıyor (İran, Kuzey Kore, Küba, tam liste sitelerinde). Default provider 'gateway' — akıllı seçici Revolut, Transak veya Banxa'ya fall-back yapar, farklı coğrafyaları kapsar. provider: 'moonpay' ile belirli bir provider sabitlediyeysen, kaldır ve router'ın seçmesine izin ver.
Wallet'ım 'paid' event'inden sonra USDC almadı
polygonscan.com/address/<your-wallet>i USDC (Polygon POS) transferler için kontrol et. Settlement %97 sana ve %3 Peptide-Pay'e düşer - %97 inbound'u görmüyorsan, init çağrısında yanlış wallet yapıştırmış olabilirsin. GET /sessions/{id} ile yeniden doğrula - txid alanı gerçek on-chain transfere işaret eder.
Müşteriden iki kez tahsilat yapıldı
Olmamalı. Her session'ın tek bir settlement addressIn'i var; aynı adrese ikinci bir ödeme bizde ayrı bir session olur ve sipariş için sadece ilkini credit ederiz. Olduysa iki polygonscan txid + session id ekran görüntüsü al ve hi@peptide-pay.com'a email at - duplicate'i hazinemizden iade ederiz.
502 'Payment infrastructure temporarily unavailable' alıyorum
Settlement upstream'imiz bozuk (request'lerin < %0.5'i). Aynı Idempotency-Key ile 30sn sonra tekrar dene - wallet başarıyla oluştuğu anda cache orijinal response'u döner. Canlı olaylar için /status takip et.

Entegrasyona hazır mısın?

Çoğu merchant sıfırdan ilk ödenen işleme 30 dakikanın altında geçiyor.