Partner API
The Kesles Merchant Partner API provides read-only access to merchant data within the partner scope (referral / consent / assignment), authenticated via partner credentials.
Base URL:
| Environment | Host |
|---|---|
| Production | https://api-merchant.kesles.com |
| Staging | https://api-merchant-staging.kesles.com |
Base path: /api/partner/v1
Auth: Partner credentials (credential_key + credential_secret) issued by the Kesles team during partner onboarding. See Partner Onboarding.
Authentication
Exchange Credentials
POST /api/partner/v1/auth/token
Exchange credentials for a short-lived access token (default 3600 seconds / 60 minutes).
Request
POST /api/partner/v1/auth/token
Content-Type: application/json
{
"credential_key": "<partner-key>",
"credential_secret": "<partner-secret>"
}
Response 200
{
"token_type": "bearer",
"access_token": "eyJhbGc...",
"expires_in": 3600,
"scopes": ["merchant.read", "transaction.read"],
"partner_id": "uuid",
"partner_code": "PTR-DEMO-001",
"partner_name": "Demo Partner"
}
Use the access_token as Authorization: Bearer <token> for all subsequent requests. The token expires after expires_in seconds; fetch a new one before expiry.
Commonly issued scopes:
| Scope | Access |
|---|---|
merchant.read | List + summary of referral merchants |
transaction.read | Transactions for merchants in partner scope |
scoring.read / risk-summary.read | Merchant scoring summary (finance partners) |
Merchant Endpoints
List Referral Merchants
GET /api/partner/v1/partners/{partner_id}/referral-merchants
Lists merchants within this partner's scope (referral, mapping, or consent).
Scope: merchant.read
Request
GET /api/partner/v1/partners/{partner_id}/referral-merchants
Authorization: Bearer {access_token}
X-Request-ID: {uuid}
Response 200
{
"partner_id": "uuid",
"items": [
{
"merchant_id": "uuid",
"merchant_code": "MRC-000123",
"merchant_name": "Sample Store",
"referral_partner_id": "uuid",
"status": "active"
}
],
"count": 1
}
| Field | Format | Notes |
|---|---|---|
merchant_id | UUID | Merchant identifier |
merchant_code | string | Kesles internal merchant code |
merchant_name | string | Merchant trade name |
referral_partner_id | UUID | null | Partner ID yang mereferral merchant ini |
status | enum | active, pending_review, inactive, suspended |
count | integer | Jumlah item yang dikembalikan |
Referral Summary
GET /api/partner/v1/partners/{partner_id}/referral-merchants/summary
Aggregate summary of referral merchants and their transaction performance.
Scope: merchant.read
Response 200
{
"partner_id": "uuid",
"merchant_count": 142,
"active_count": 98,
"inactive_count": 44
}
| Field | Format | Notes |
|---|---|---|
merchant_count | integer | Total merchants in partner scope |
active_count | integer | Merchants dengan status = active |
inactive_count | integer | Merchants dengan status selain active |
Merchant Transactions
GET /api/partner/v1/merchants/{merchant_id}/transactions
Lists merchant transactions (only merchants within the partner scope).
Scope: transaction.read
Request
GET /api/partner/v1/merchants/{merchant_id}/transactions?transaction_at_from=2026-04-01T00:00:00Z&transaction_at_to=2026-04-30T23:59:59Z&status=success&limit=50
Authorization: Bearer {access_token}
X-Request-ID: {uuid}
Query params:
| Param | Type | Default | Notes |
|---|---|---|---|
transaction_at_from | RFC3339 | — | Filter awal waktu transaksi (inklusif) |
transaction_at_to | RFC3339 | — | Filter akhir waktu transaksi (inklusif) |
status | string | — | Filter by status: success, pending, failed, refunded |
limit | integer | 50 | Jumlah item, maksimal 500 |
The backend hard-caps responses at 500 items. For high-volume date ranges, use narrower windows via transaction_at_from / transaction_at_to.
Response 200
{
"merchant_id": "uuid",
"items": [
{
"id": "uuid",
"merchant_id": "uuid",
"transaction_code": "TRX-2026-04-000412",
"transaction_status": "success",
"payment_method": "qris",
"payment_channel": "bca",
"gross_amount": 75000,
"mdr_rate": 0.007,
"mdr_fee_amount": 525,
"net_amount_after_mdr": 74475,
"currency": "IDR",
"transaction_at": "2026-04-24T10:15:28Z",
"settled_at": "2026-04-25T08:00:00+07:00",
"settlement_status": "settled"
}
],
"count": 1
}
Per-item fields:
| Field | Format | Notes |
|---|---|---|
id | UUID | Transaction identifier |
merchant_id | UUID | Merchant identifier |
transaction_code | string | Kesles internal code |
transaction_status | enum | success, pending, failed, refunded |
payment_method | string | qris, card, cash, etc. |
payment_channel | string | Channel/issuer (e.g. bca, mandiri) |
gross_amount | integer | Gross amount (smallest currency unit) |
mdr_rate | decimal | MDR rate yang dikenakan |
mdr_fee_amount | integer | Nominal biaya MDR (smallest currency unit) |
net_amount_after_mdr | integer | Gross amount dikurangi MDR fee |
currency | ISO 4217 | Default IDR |
transaction_at | RFC3339 | Waktu transaksi (full timestamp) |
settled_at | RFC3339 | null | Settlement time; null when not yet settled |
settlement_status | string | Status settlement transaksi |
Internal fields not returned: customer_id, qris_payload, raw device_id, gateway-side merchant/terminal identifiers, payer_reference, and internal fee-share components.
Merchant Scoring Summary
GET /api/partner/v1/merchants/{merchant_id}/scoring-summary
A transaction-based business scoring summary — intended for finance / scoring underwriting partners, not for free-form merchant data access.
Scope: scoring.read or risk-summary.read
Response 200
{
"merchant_id": "uuid",
"average_monthly_gross_amount": 78500000,
"average_monthly_transaction_count": 412,
"avg_ticket_size": 190534,
"growth_30d": 8.2,
"settlement_consistency_score": 95,
"transaction_stability_score": 90,
"months_sampled": 3
}
| Field | Format | Notes |
|---|---|---|
average_monthly_gross_amount | integer | Gross amount bulan terakhir (smallest currency unit) |
average_monthly_transaction_count | integer | Jumlah transaksi bulan terakhir |
avg_ticket_size | integer | Rata-rata nilai transaksi bulan terakhir |
growth_30d | decimal | Pertumbuhan gross amount vs bulan sebelumnya dalam persen (8.2 = +8.2%) |
settlement_consistency_score | integer 0–100 | Skor konsistensi transaksi dalam stepped buckets: 95 / 85 / 70 / 55 / 35 |
transaction_stability_score | integer 0–100 | Skor stabilitas volume transaksi dalam stepped buckets: 90 / 75 / 60 / 40 |
months_sampled | integer | Jumlah bulan data yang digunakan untuk kalkulasi |
Internal fields not returned: user NIK, account_number, raw payer_reference, personal identity details.
Error Codes
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | Invalid payload / query param |
| 401 | unauthorized | Credential or access token invalid / expired |
| 403 | forbidden | Partner missing scope, or merchant outside partner scope |
| 404 | (none) | Unknown endpoint |
| 429 | rate_limit_exceeded | Per-credential rate limit exceeded |
| 500 | internal_error | Server error — retry with exponential backoff |
Error body format:
{
"error": "human readable message",
"code": "machine_readable_code",
"retry_after_secs": 60
}
retry_after_secs is only present for 429 or other retryable errors.
Rate Limit
- Default 60 requests / minute / credential
- Response headers:
X-RateLimit-Remaining,X-RateLimit-Reset(Unix seconds) - 429 responses include
retry_after_secsin the body + aRetry-Afterheader
Data Access Scope
A partner can only see merchants that are:
- Referred by the partner (via
referral_codematching the partner) - Granted explicit consent to the partner
- Manually assigned by a Kesles operator
A partner cannot:
- Access merchant data outside the scope above →
403 forbidden - Create / update / delete merchant data
- Access Kesles admin / internal endpoints
- Access terminal, pairing, or device-control endpoints
Data Masking Policy
To protect merchant transaction data, sensitive fields are filtered before being returned:
| Internal field | Status in Partner API | Reason |
|---|---|---|
customer_id | Not returned | Buyer privacy |
qris_payload | Not returned | Sensitive payment payload |
| Gateway-side merchant/terminal identifiers | Not returned | Internal routing |
Raw payer_reference | Not returned | Buyer privacy |
| User NIK / account_number | Not returned in scoring summary | PII / banking data |
Per-transaction MDR breakdown (mdr_rate, mdr_fee_amount, net_amount_after_mdr) | Returned | Tersedia untuk rekonsiliasi partner |
| Internal service-fee components | Not returned | Kesles–merchant commercial secret |
| Kesles–merchant–partner fee-share / commission | Not returned | Commercial secret; reconciled via the Partner Agreement channel |
HMAC-Signed Endpoints
The standard Partner API endpoints (above) use Bearer JWT, or HMAC-signed-per-request, depending on the credential configuration issued at onboarding. For certain server-to-server integrations (outside the public endpoint scope above), Kesles provides a separate API contract that is not published in the public documentation and is shared per partner via the Partner Agreement + an encrypted onboarding channel. For signature pattern & headers, see HMAC Authentication.
Changelog
Breaking changes to the Partner API will be version-bumped (/api/partner/v1 → /api/partner/v2) with a minimum 90-day grace period. Subscribe to the partner mailing list for change notifications.