Skip to main content

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:

EnvironmentHost
Productionhttps://api-merchant.kesles.com
Staginghttps://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:

ScopeAccess
merchant.readList + summary of referral merchants
transaction.readTransactions for merchants in partner scope
scoring.read / risk-summary.readMerchant 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
}
FieldFormatNotes
merchant_idUUIDMerchant identifier
merchant_codestringKesles internal merchant code
merchant_namestringMerchant trade name
referral_partner_idUUID | nullPartner ID yang mereferral merchant ini
statusenumactive, pending_review, inactive, suspended
countintegerJumlah 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
}
FieldFormatNotes
merchant_countintegerTotal merchants in partner scope
active_countintegerMerchants dengan status = active
inactive_countintegerMerchants 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:

ParamTypeDefaultNotes
transaction_at_fromRFC3339Filter awal waktu transaksi (inklusif)
transaction_at_toRFC3339Filter akhir waktu transaksi (inklusif)
statusstringFilter by status: success, pending, failed, refunded
limitinteger50Jumlah 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:

FieldFormatNotes
idUUIDTransaction identifier
merchant_idUUIDMerchant identifier
transaction_codestringKesles internal code
transaction_statusenumsuccess, pending, failed, refunded
payment_methodstringqris, card, cash, etc.
payment_channelstringChannel/issuer (e.g. bca, mandiri)
gross_amountintegerGross amount (smallest currency unit)
mdr_ratedecimalMDR rate yang dikenakan
mdr_fee_amountintegerNominal biaya MDR (smallest currency unit)
net_amount_after_mdrintegerGross amount dikurangi MDR fee
currencyISO 4217Default IDR
transaction_atRFC3339Waktu transaksi (full timestamp)
settled_atRFC3339 | nullSettlement time; null when not yet settled
settlement_statusstringStatus 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
}
FieldFormatNotes
average_monthly_gross_amountintegerGross amount bulan terakhir (smallest currency unit)
average_monthly_transaction_countintegerJumlah transaksi bulan terakhir
avg_ticket_sizeintegerRata-rata nilai transaksi bulan terakhir
growth_30ddecimalPertumbuhan gross amount vs bulan sebelumnya dalam persen (8.2 = +8.2%)
settlement_consistency_scoreinteger 0–100Skor konsistensi transaksi dalam stepped buckets: 95 / 85 / 70 / 55 / 35
transaction_stability_scoreinteger 0–100Skor stabilitas volume transaksi dalam stepped buckets: 90 / 75 / 60 / 40
months_sampledintegerJumlah bulan data yang digunakan untuk kalkulasi

Internal fields not returned: user NIK, account_number, raw payer_reference, personal identity details.

Error Codes

StatusCodeMeaning
400bad_requestInvalid payload / query param
401unauthorizedCredential or access token invalid / expired
403forbiddenPartner missing scope, or merchant outside partner scope
404(none)Unknown endpoint
429rate_limit_exceededPer-credential rate limit exceeded
500internal_errorServer 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_secs in the body + a Retry-After header

Data Access Scope

A partner can only see merchants that are:

  1. Referred by the partner (via referral_code matching the partner)
  2. Granted explicit consent to the partner
  3. 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 fieldStatus in Partner APIReason
customer_idNot returnedBuyer privacy
qris_payloadNot returnedSensitive payment payload
Gateway-side merchant/terminal identifiersNot returnedInternal routing
Raw payer_referenceNot returnedBuyer privacy
User NIK / account_numberNot returned in scoring summaryPII / banking data
Per-transaction MDR breakdown (mdr_rate, mdr_fee_amount, net_amount_after_mdr)ReturnedTersedia untuk rekonsiliasi partner
Internal service-fee componentsNot returnedKesles–merchant commercial secret
Kesles–merchant–partner fee-share / commissionNot returnedCommercial 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.