Lewati ke konten utama

PSP Integration Contract

Kontrak teknis untuk PSP yang terintegrasi dengan platform Kesles Merchant.

Confidential

Dokumen ini hanya untuk pihak yang sudah memiliki NDA dengan Kesles. Jangan disebarkan.

1. Prinsip Dasar

  1. Read-only — PSP hanya memiliki akses GET ke data merchant via Lookup API. Write endpoint (NMID assignment, payment events) memerlukan akses Tier-1 Internal.
  2. Data isolation — setiap bank hanya melihat merchant yang NMID-nya diterbitkan oleh acquirer tersebut. Bank A tidak bisa melihat merchant Bank B.
  3. Active-only — hanya merchant dengan status = active, deleted_at IS NULL, dan nmid IS NOT NULL yang dikembalikan.
  4. Idempotent — semua request aman untuk di-retry (gunakan X-Request-ID).
  5. Eventual consistency — data bisa lag ≤30 detik.

2. Authentication — HMAC-SHA256

Header auth berbeda tergantung service yang dituju:

2.1 Lookup API — dashboard_api (port 8082)

Berlaku untuk: GET /api/psp/v1/merchants/*

X-API-Key-ID: <public key identifier — aman untuk di-log>
X-Timestamp: <unix seconds, waktu sekarang>
X-Signature: hmac-sha256=<computed signature>
X-Request-ID: <uuid v4 untuk tracing>

2.2 Events API — payment-service (port 8085)

Berlaku untuk: POST /psp/v1/events, POST /psp/v1/settlements

X-PSP-Key-ID: <public key identifier — aman untuk di-log>
X-PSP-Timestamp: <RFC3339 timestamp, waktu sekarang — contoh 2026-06-08T10:30:00+07:00>
X-PSP-Signature: <computed signature — raw hex, tanpa prefix>
X-Request-ID: <uuid v4 untuk tracing>

2.3 Cara Menghitung Signature

Lookup API — string-to-sign: {timestamp}\n{method}\n{path}\n{body}

Contoh untuk GET /api/psp/v1/merchants/by-nmid/ID102326873XXXX:

1716452580
GET
/api/psp/v1/merchants/by-nmid/ID102326873XXXX

(Body kosong untuk GET; trailing newline tetap ada)

Events API — string-to-sign: {method}\n{path}\n{timestamp}\n{body}timestamp berformat RFC3339 (sama dengan header X-PSP-Timestamp).

Contoh untuk POST /psp/v1/events:

POST
/psp/v1/events
2026-06-08T10:30:00+07:00
{"external_event_id":"psp-evt-abc-123","event_type":"transaction.success",...}

Penting: urutan field di signed_payload berbeda antara dua service. Lookup API memakai unix seconds; Events API memakai RFC3339. Pastikan menggunakan format yang benar sesuai endpoint tujuan.

Compute HMAC-SHA256 (sama untuk keduanya — kembalikan raw hex; hanya Lookup API yang menambahkan prefix hmac-sha256=):

// Go
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(stringToSign))
signature := hex.EncodeToString(mac.Sum(nil))
# Python
import hmac, hashlib
sig = hmac.new(secret.encode(), string_to_sign.encode(), hashlib.sha256)
signature = sig.hexdigest()
// Node.js
const crypto = require('crypto');
const signature = crypto.createHmac('sha256', secret).update(stringToSign).digest('hex');

2.4 Validasi yang Dilakukan Server

Server melakukan 5 pengecekan sebelum memproses request:

  1. Key ID (X-API-Key-ID atau X-PSP-Key-ID) valid dan terdaftar
  2. Timestamp freshness — ditolak jika |now - timestamp| > 300 detik (cegah replay attack)
  3. HMAC signature cocok (constant-time comparison)
  4. IP caller ada di allowlist (jika dikonfigurasi)
  5. Rate limit per API Key ID

Jika salah satu gagal: server mengembalikan 401 atau 403 tanpa detail spesifik.

2.5 API Key Rotation

  • Rotasi setiap 90 hari — jadwal disepakati saat onboarding
  • Grace period 7 hari — dua key aktif bersamaan saat rotasi
  • Revokasi instan via tim Kesles — semua request dengan key lama langsung 401
  • Secret dikirim ulang via saluran aman (1Password / Bitwarden), tidak pernah via email

3. Base URL

Production : https://api-merchant.kesles.com
Staging : https://api-merchant-staging.kesles.com

4. Endpoint yang Tersedia

4.1 Merchant Lookup (Lookup API — dashboard_api)

MethodPathDeskripsi
GET/api/psp/v1/merchantsList semua merchant aktif (cursor paginated)
GET/api/psp/v1/merchants/{id}Detail merchant by UUID
GET/api/psp/v1/merchants/by-nmid/{nmid}Lookup merchant by NMID (hot endpoint)
GET/api/psp/v1/merchants/searchCari merchant by phone/email/npwp

4.2 Payment Events (Events API — payment-service)

MethodPathDeskripsi
POST/psp/v1/eventsForward payment event (transaction, refund, nmid-status-changed)
POST/psp/v1/settlementsForward batch settlement harian
Endpoint Tidak Tersedia untuk PSP Eksternal

Endpoint berikut dibatasi untuk PSP Internal Tier-1 dan akan mengembalikan 403 untuk PSP bank eksternal:

  • PATCH /api/psp/v1/merchants/{id}/nmid-assignment

Respons Error

CodeArti
400Body request malformed atau nilai field tidak valid
401Header autentikasi hilang atau tidak valid
403Key valid tapi tidak diizinkan untuk endpoint ini
429Rate limit terlampaui — terapkan exponential backoff
500Kegagalan infrastruktur sementara (DB timeout, service unavailable). PSP WAJIB retry dengan exponential backoff untuk respons 500.
Event duplikat bukan error

external_event_id yang duplikat bukan 409 (atau error apa pun). Server bersifat idempoten: server membalas HTTP 200 dengan body {"status":"duplicate_skipped"} (opsional disertai field "message"). Perlakukan ini sebagai event yang sudah berhasil diproses — aman untuk diabaikan.

5. Rate Limits

EndpointLimit
GET /merchants60 req/menit per API key
GET /merchants/{id}600 req/menit per API key
GET /merchants/by-nmid/{nmid}1.000 req/menit per API key
GET /merchants/search120 req/menit per API key
POST /psp/v1/events6.000 req/menit per API key
POST /psp/v1/settlements600 req/menit per API key

Respons 429 jika melebihi limit. Implementasikan exponential backoff.

6. Format Error Standard

{
"error": "human readable message",
"code": "machine_readable_code"
}

Lihat Error Codes untuk daftar lengkap.