Developer Documentation

Integrasikan pembayaran melalui satu API.

Client berkomunikasi hanya dengan Payantara. Konfigurasi pemrosesan internal tidak mengubah kontrak API client.

Base URL: https://gateway.payantara.com JSON API HMAC-SHA256 Webhooks

Quick Start

Gunakan credential SANDBOX untuk pengujian dan credential LIVE untuk transaksi produksi. Endpoint tetap sama; mode mengikuti API key project.
curl -X POST "https://gateway.payantara.com/api/v1/payments" \
  -H "Content-Type: application/json" \
  -H "X-Public-Key: pk_sandbox_xxxxxxxxx" \
  -H "Authorization: Bearer sk_sandbox_xxxxxxxxx" \
  -H "Idempotency-Key: ORDER-1001" \
  -d '{
    "order_id": "ORDER-1001",
    "amount": 10000,
    "payment_method": "QRIS",
    "customer_name": "Budi",
    "customer_email": "budi@example.com",
    "customer_phone": "081234567890",
    "expire_minutes": 15
  }'

Authentication

Kirim Public Key dan Secret API Key project pada setiap request yang membutuhkan autentikasi. Jangan menaruh secret di browser, aplikasi mobile, repository, atau log publik.

X-Public-Key: pk_live_xxxxxxxxx
Authorization: Bearer sk_live_xxxxxxxxx
Content-Type: application/json

Public key pk_... mengidentifikasi credential. Secret key sk_... membuktikan autentikasi server-to-server. Header X-Secret-Key dapat digunakan sebagai fallback bila server client tidak meneruskan header Authorization.

Rate Limiting

Request dibatasi berdasarkan alamat IP dan API key. Saat batas terlampaui, API mengembalikan HTTP 429. Terapkan exponential backoff dan jangan melakukan retry agresif.

Idempotency

Gunakan nilai unik dan stabil untuk setiap order. Mengulang request dengan key yang sama mencegah pembuatan pembayaran ganda.

Idempotency-Key: ORDER-1001

Payments

Resource pembayaran utama memakai path /api/v1/payments. Endpoint yang tersedia saat ini adalah create, get status, dan cancel payment.

Create Payment

POST/api/v1/payments
FieldTypeRequiredKeterangan
order_idstringYaID order unik dari sistem client.
amountnumberYaNominal pembayaran dalam rupiah.
payment_methodstringYaKode channel dari endpoint payment methods.
customer_namestringTidakNama pembayar.
customer_emailstringTidakEmail pembayar.
customer_phonestringTidakNomor telepon pembayar.
expire_minutesintegerTidakDurasi kedaluwarsa pembayaran.
return_urlURLTidakURL tujuan setelah checkout.

Get Payment Status

GET/api/v1/payments/{transaction_id_or_order_id}
curl "https://gateway.payantara.com/api/v1/payments/ORDER-1001" \
  -H "X-Public-Key: pk_live_xxxxxxxxx" \
  -H "Authorization: Bearer sk_live_xxxxxxxxx"

Cancel Pending Payment

POST/api/v1/payments/{transaction_id_or_order_id}/cancel

Cancel hanya berlaku untuk pembayaran yang masih dapat dibatalkan. Pembayaran yang sudah final tidak dapat dibatalkan melalui endpoint ini.

Payment Status

StatusArti
PENDINGMenunggu pembayaran.
PAIDPembayaran berhasil dan final.
EXPIREDPembayaran melewati batas waktu atau dibatalkan.
FAILEDPembayaran tidak dapat diproses.

Payment Channels & Fees

GET/api/v1/payment-methods

Gunakan endpoint ini sebagai sumber kebenaran untuk daftar channel, status ketersediaan, batas nominal, biaya, dan masa berlaku. Jangan hard-code ketersediaan channel.

curl "https://gateway.payantara.com/api/v1/payment-methods" \
  -H "X-Public-Key: pk_live_xxxxxxxxx" \
  -H "Authorization: Bearer sk_live_xxxxxxxxx"
QRIS
Gunakan kode channel yang dikembalikan API. Response create payment dapat memuat checkout URL atau QR string.
Virtual Account & E-Wallet
Tampilkan hanya bila channel dikembalikan dalam keadaan aktif untuk project Anda.

Payment Instructions

Response create payment dapat berbeda menurut channel. Render field yang tersedia, seperti:

  • payment_url atau checkout URL;
  • qr_string untuk QRIS;
  • va_number untuk Virtual Account;
  • instructions untuk langkah pembayaran;
  • expires_at untuk batas waktu pembayaran.

Webhooks

Payantara mengirim perubahan status ke callback URL project. Receiver harus menggunakan HTTPS, memverifikasi signature, memeriksa timestamp, dan menyimpan idempotency key.

X-Payantara-Webhook-Id: wh_xxx
X-Payantara-Idempotency-Key: idem_xxx
X-Payantara-Event: payment.paid
X-Payantara-Timestamp: 1780000000
X-Payantara-Signature: t=1780000000,v1=<hmac_sha256_hex>
X-Payantara-Signature-Version: v1
X-Payantara-Delivery-Attempt: 1

Events

EventKeterangan
payment.paidPayment berubah menjadi PAID.
payment.expiredPayment berubah menjadi EXPIRED.
webhook.testEvent pengujian dari Developer Center.

PHP Signature Verification

<?php
$secret = getenv('PAYANTARA_WEBHOOK_SECRET') ?: '';
$rawBody = file_get_contents('php://input');
$timestamp = (int)($_SERVER['HTTP_X_PAYANTARA_TIMESTAMP'] ?? 0);
$signature = $_SERVER['HTTP_X_PAYANTARA_SIGNATURE'] ?? '';
$idempotencyKey = $_SERVER['HTTP_X_PAYANTARA_IDEMPOTENCY_KEY'] ?? '';

if (!$timestamp || abs(time() - $timestamp) > 300) {
    http_response_code(400);
    exit('stale');
}

$expected = 't=' . $timestamp . ',v1=' .
    hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('invalid signature');
}

// Simpan $idempotencyKey sebelum memproses event.
http_response_code(200);
echo json_encode(['success' => true]);

Error Codes

Client hanya menerima kontrak error Payantara. Detail teknis internal tidak dikirim melalui response API, webhook, dokumentasi, atau dashboard client.

{
  "success": false,
  "error": {
    "code": "PAYMENT_PROCESSING_FAILED",
    "message": "Payment could not be processed. Please try again."
  },
  "request_id": "req_xxxxxxxxx"
}
HTTPCodeKeterangan
400INVALID_REQUESTRequest tidak dapat dibaca.
401AUTHENTICATION_FAILEDAPI key tidak valid atau tidak aktif.
404PAYMENT_NOT_FOUNDPayment tidak ditemukan untuk project tersebut.
422VALIDATION_FAILEDField request tidak valid.
429RATE_LIMITEDTerlalu banyak request.
503PAYMENT_PROCESSING_FAILEDPayment belum dapat diproses.
503PAYMENT_CANCEL_FAILEDPayment belum dapat dibatalkan.