Skip to content

Enterprise KYB ​

A company signs up, gets a sandbox workspace at once, and verifies the business through one KYB application: the company details, the people, the bank account and the documents. RekberPay reviews it in 1 to 3 business days. On approval the workspace switches to Live by itself. The same application, opened from a verification link, verifies a counterparty. The flow is walked through in Verify your business. Auth, roles, the workspace header and the shared limits are explained in Enterprise overview.

Statuses ​

Application statusMeaningWorkspace kyb_statusCounterparty kyb_status
draftBeing filled in, or reopened after changes were requestednot_started, or draft after a change requestnot_started or pending
submittedWaiting for reviewpendingpending
changes_requestedA reviewer asked for changes; a new draft version holds change_requestsdraftpending
approvedVerified. The workspace is Liveverifiedverified
rejectedNot approved. decision_reason says why; saving again starts a new versionrejectedrejected

Every version is kept. version counts up each time changes are requested or a rejected application is started again.

Identity data ​

NIK and passport numbers are encrypted at rest (AES-256-GCM) and are never returned: answers carry id_number_last4 only. The company bank account comes back as account_number_last4. Documents are private files served only by 5 minute links signed for one user.

Endpoints ​

MethodPathEndpointAuth
POST/v1/enterprise/registerCreate a workspaceAny signed-in user, dashboard only
GET/v1/enterprise/kybGet the KYB applicationAny member; full view finance and up
PATCH/v1/enterprise/kybSave the draftadmin, dashboard only
POST/v1/enterprise/kyb/uploadsUpload a document fileadmin, dashboard only
POST/v1/enterprise/kyb/documentsAttach a documentadmin, dashboard only
DELETE/v1/enterprise/kyb/documents/:idRemove a documentadmin, dashboard only
GET/v1/enterprise/kyb/documents/:id/urlGet a document linkadmin, dashboard only
POST/v1/enterprise/kyb/submitSubmit for reviewadmin, dashboard only
POST/v1/enterprise/counterparties/:id/kyb-inviteSend a counterparty verification linkadmin, dashboard only
GET/v1/kyb/invite/:tokenOpen a verification linkThe link's user, dashboard only
PATCH/v1/kyb/invite/:tokenSave a counterparty draftThe link's user, dashboard only
POST/v1/kyb/invite/:token/uploadsUpload a counterparty document fileThe link's user, dashboard only
POST/v1/kyb/invite/:token/documentsAttach a counterparty documentThe link's user, dashboard only
DELETE/v1/kyb/invite/:token/documents/:idRemove a counterparty documentThe link's user, dashboard only
GET/v1/kyb/invite/:token/documents/:id/urlGet a counterparty document linkThe link's user, dashboard only
POST/v1/kyb/invite/:token/submitSubmit a counterparty applicationThe link's user, dashboard only

Create a workspace ​

POST/v1/enterprise/register

Creates a workspace for your company with you as its owner. It starts in the sandbox with kyb_status: "not_started" and a draft KYB application (version 1) that already holds the legal name, entity type and NIB, so Get the KYB application opens half filled. One account can own at most 3 workspaces (an operator setting).

  • Auth: Dashboard session of any signed-in user, no workspace needed. API keys get 403 KEY_NOT_ALLOWED.
  • Rate limit: 5 an hour per user and 10 an hour per IP address for this route, plus the shared 300 a minute.
  • Idempotency: Not supported. A retry creates another workspace, up to the limit.

Body (JSON) ​

NameTypeRequiredDescription
legal_namestringYes2 to 180 characters, as on the deed
display_namestringYes2 to 120 characters, the name your team sees
entity_typestringYespt, pt_perorangan, cv, firma, koperasi, ud or foreign
nibstringYesNIB, 13 digits. For foreign, the home registration number (3 to 40 characters)
country_codestringNoISO country code, default ID. Must be ID for Indonesian entities and another country for foreign
turnstile_tokenstringWhen enabledThe Cloudflare Turnstile token from the sign-up form

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/enterprise/register \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
      "legal_name": "PT Sinar Laut Logistik",
      "display_name": "Sinar Laut Logistik",
      "entity_type": "pt",
      "nib": "9120001234567",
      "turnstile_token": "0.turnstile-token"
  }'
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/register', {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        "legal_name": "PT Sinar Laut Logistik",
        "display_name": "Sinar Laut Logistik",
        "entity_type": "pt",
        "nib": "9120001234567",
        "turnstile_token": "0.turnstile-token"
    }),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
    "https://api.rekberpay.com/v1/enterprise/register",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
    },
    json={
        "legal_name": "PT Sinar Laut Logistik",
        "display_name": "Sinar Laut Logistik",
        "entity_type": "pt",
        "nib": "9120001234567",
        "turnstile_token": "0.turnstile-token"
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/register');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'legal_name' => 'PT Sinar Laut Logistik',
        'display_name' => 'Sinar Laut Logistik',
        'entity_type' => 'pt',
        'nib' => '9120001234567',
        'turnstile_token' => '0.turnstile-token',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

201 Created

json
{
    "success": true,
    "data": {
        "account": {
            "id": "8fc61a2b-dbf6-4070-a570-aaa2a6560d02",
            "legal_name": "PT Sinar Laut Logistik MV6XWDGH",
            "display_name": "Sinar Laut MV6XWDGH",
            "country_code": "ID",
            "kyb_status": "not_started",
            "risk_tier": "standard",
            "is_sandbox": true
        },
        "membership": {
            "id": "1c3f191e-3287-4896-b6aa-05572d7ddb49",
            "role": "owner"
        },
        "kyb_application": {
            "id": "09c9e6db-ddb2-48b0-ad86-4122b24ebb8c",
            "version": 1,
            "status": "draft"
        }
    }
}

Errors ​

StatusCodeCause
400INVALID_BODYA field is missing or has the wrong format, see error.details
403TURNSTILE_FAILEDThe Turnstile check did not pass
403KEY_NOT_ALLOWEDCalled with an API key instead of a dashboard session
409WORKSPACE_LIMITYou already own the most workspaces one account may own
409TRY_AGAINAnother sign-up for your account is still running
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Get the KYB application ​

GET/v1/enterprise/kyb

The workspace's current application (the highest version), with progress, the document slots for its entity type and the history of earlier versions. Identity numbers come back as their last 4 digits only.

Owners, admins and finance get the full view (view: "full"). operator and viewer members and every API key get only the status (view: "status"): the subject's kyb_status and the application's status, version, submitted_at and decided_at.

  • Auth: A workspace API key (status only), a personal API key or a dashboard session.
  • Role: Any member. The full view needs finance, admin or owner and a dashboard session.
  • Rate limit: 120 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. Reading has no side effects.

Example request ​

bash
curl https://api.rekberpay.com/v1/enterprise/kyb \
  -H "Authorization: Bearer $REKBERPAY_WORKSPACE_KEY"
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/kyb', {
    headers: {
        Authorization: `Bearer ${process.env.REKBERPAY_WORKSPACE_KEY}`,
    },
});
const data = await res.json();
python
import os

import requests

resp = requests.get(
    "https://api.rekberpay.com/v1/enterprise/kyb",
    headers={
        "Authorization": f"Bearer {os.environ['REKBERPAY_WORKSPACE_KEY']}",
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/kyb');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('REKBERPAY_WORKSPACE_KEY'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "account",
            "id": "8fc61a2b-dbf6-4070-a570-aaa2a6560d02",
            "name": "Sinar Laut MV6XWDGH",
            "kyb_status": "draft",
            "is_sandbox": true,
            "account_manager": null
        },
        "application": {
            "id": "61b95d77-3a11-4d25-ba85-27437db152ea",
            "version": 2,
            "status": "draft",
            "entity_type": "pt",
            "legal_name": "PT Sinar Laut Logistik MV6XWDGH",
            "country_code": "ID",
            "nib": "9120911597635",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Sinar Laut Logistik MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "7d0392ef-c14d-4836-9ea6-2746d6f98486",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "80e13305-314e-49c7-8068-c5666d60177e",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [
                {
                    "id": "c4682fbc-deb9-4978-8cc9-fc05b9d8e963",
                    "doc_type": "akta_pendirian",
                    "person_id": null,
                    "original_name": "akta_pendirian.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 166,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.843Z"
                },
                {
                    "id": "10a0d3f0-225e-48a8-bcf4-89abfbe14d9b",
                    "doc_type": "bank_proof",
                    "person_id": null,
                    "original_name": "bank_proof.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 162,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.843Z"
                }
            ],
            "change_requests": [
                {
                    "item": "doc:npwp",
                    "label": "NPWP badan",
                    "reason": "The NPWP photo is blurred."
                }
            ],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.842Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": false
            },
            "done": 3,
            "total": 4,
            "missing_documents": [
                {
                    "key": "npwp",
                    "type": "npwp",
                    "label": "NPWP badan",
                    "hint": "The company tax card or certificate.",
                    "required": true,
                    "person_id": null
                }
            ],
            "complete": false
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 2,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            },
            {
                "version": 1,
                "status": "changes_requested",
                "submitted_at": "2026-10-13T17:13:17.801Z",
                "decided_at": "2026-10-13T17:13:17.841Z",
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Save the draft ​

PATCH/v1/enterprise/kyb

Saves any of the three parts of the draft. Send only what changed: company fields are merged, people replaces the whole list (keep a person's id to keep their stored identity number when you leave id_number out), and bank fields are merged. Formats are checked on save: NIB 13 digits, NPWP 15 or 16 digits, NIK 16 digits with a valid province code and birth date, passport 6 to 12 letters and digits.

A submitted application cannot be edited (409 APPLICATION_LOCKED). After a rejection, the first save starts a new version from the rejected one.

  • Auth: Dashboard session with X-CSRF-Token on writes. API keys get 403 KEY_NOT_ALLOWED: KYB is filled in by people, not integrations.
  • Role: admin or owner.
  • Rate limit: 120 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. Saving the same body twice leaves the same draft.

Body (JSON) ​

NameTypeRequiredDescription
companyobjectNoentity_type, legal_name, country_code, nib, npwp, address, industry, monthly_volume (under_1b, 1b_10b, 10b_50b or over_50b), website
peoplearrayNoUp to 20 people: id (keep to update), full_name, position, roles (director, signer, beneficial_owner), id_type (nik or passport), id_number, nationality, ownership_pct (25 to 100 for beneficial owners)
bankobjectNobank_name, bank_account_holder (should match the legal name), account_number

Example request ​

bash
curl -X PATCH https://api.rekberpay.com/v1/enterprise/kyb \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "X-Enterprise-Account: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
      "company": {
          "npwp": "01.234.567.8-901.000",
          "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
          "industry": "Logistics",
          "monthly_volume": "1b_10b"
      },
      "people": [
          {
              "full_name": "Ayu Pratiwi",
              "position": "President Director",
              "roles": [
                  "director",
                  "signer",
                  "beneficial_owner"
              ],
              "id_type": "nik",
              "id_number": "3171015505900001",
              "ownership_pct": 60
          }
      ],
      "bank": {
          "bank_name": "BCA",
          "bank_account_holder": "PT Sinar Laut Logistik",
          "account_number": "1234567890"
      }
  }'
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/kyb', {
    method: 'PATCH',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'X-Enterprise-Account': process.env.WORKSPACE_ID,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        "company": {
            "npwp": "01.234.567.8-901.000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b"
        },
        "people": [
            {
                "full_name": "Ayu Pratiwi",
                "position": "President Director",
                "roles": [
                    "director",
                    "signer",
                    "beneficial_owner"
                ],
                "id_type": "nik",
                "id_number": "3171015505900001",
                "ownership_pct": 60
            }
        ],
        "bank": {
            "bank_name": "BCA",
            "bank_account_holder": "PT Sinar Laut Logistik",
            "account_number": "1234567890"
        }
    }),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.patch(
    "https://api.rekberpay.com/v1/enterprise/kyb",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
        "X-Enterprise-Account": os.environ["WORKSPACE_ID"],
    },
    json={
        "company": {
            "npwp": "01.234.567.8-901.000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b"
        },
        "people": [
            {
                "full_name": "Ayu Pratiwi",
                "position": "President Director",
                "roles": [
                    "director",
                    "signer",
                    "beneficial_owner"
                ],
                "id_type": "nik",
                "id_number": "3171015505900001",
                "ownership_pct": 60
            }
        ],
        "bank": {
            "bank_name": "BCA",
            "bank_account_holder": "PT Sinar Laut Logistik",
            "account_number": "1234567890"
        }
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/kyb');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'X-Enterprise-Account: ' . getenv('WORKSPACE_ID'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'company' => [
            'npwp' => '01.234.567.8-901.000',
            'address' => 'Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310',
            'industry' => 'Logistics',
            'monthly_volume' => '1b_10b',
        ],
        'people' => [
            [
                'full_name' => 'Ayu Pratiwi',
                'position' => 'President Director',
                'roles' => [
                    'director',
                    'signer',
                    'beneficial_owner',
                ],
                'id_type' => 'nik',
                'id_number' => '3171015505900001',
                'ownership_pct' => 60,
            ],
        ],
        'bank' => [
            'bank_name' => 'BCA',
            'bank_account_holder' => 'PT Sinar Laut Logistik',
            'account_number' => '1234567890',
        ],
    ]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "account",
            "id": "8fc61a2b-dbf6-4070-a570-aaa2a6560d02",
            "name": "Sinar Laut MV6XWDGH",
            "kyb_status": "not_started",
            "is_sandbox": true,
            "account_manager": null
        },
        "application": {
            "id": "09c9e6db-ddb2-48b0-ad86-4122b24ebb8c",
            "version": 1,
            "status": "draft",
            "entity_type": "pt",
            "legal_name": "PT Sinar Laut Logistik MV6XWDGH",
            "country_code": "ID",
            "nib": "9120911597635",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Sinar Laut Logistik MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "e5bea0ba-c7ae-4387-bf5f-862d6c50fafa",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "99c7a474-8ca2-497b-acb6-3121a17041c7",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [],
            "change_requests": [],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.664Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": false
            },
            "done": 3,
            "total": 4,
            "missing_documents": [
                {
                    "key": "akta_pendirian",
                    "type": "akta_pendirian",
                    "label": "Akta pendirian",
                    "hint": "The deed of establishment.",
                    "required": true,
                    "person_id": null
                },
                {
                    "key": "sk_kemenkumham",
                    "type": "sk_kemenkumham",
                    "label": "SK Kemenkumham",
                    "hint": "The Ministry of Law approval for the deed.",
                    "required": true,
                    "person_id": null
                }
            ],
            "complete": false
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 1,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
400INVALID_BODYA field has the wrong format, see error.details
403FORBIDDENYour role cannot edit the application
403KEY_NOT_ALLOWEDCalled with an API key instead of a dashboard session
409APPLICATION_LOCKEDThe application is submitted and waiting for review
409ALREADY_VERIFIEDThe workspace is already verified
409CONCURRENT_MODIFICATIONThe application changed while saving. Reload and try again
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Upload a document file ​

POST/v1/enterprise/kyb/uploads

Uploads one file and returns an upload_id to attach with Attach a document. Send multipart/form-data with one part named file.

Accepted: PDF, JPG, PNG and WebP up to 10 MB. The type is read from the file content and must match both the file name and the part's Content-Type. Images are capped at 8000 pixels a side and re-encoded, which removes EXIF and location data. PDFs with a password, scripts, automatic actions or attachments are refused. Files are private: they are never served from a public URL.

  • Auth: Dashboard session with X-CSRF-Token on writes. API keys get 403 KEY_NOT_ALLOWED: KYB is filled in by people, not integrations.
  • Role: admin or owner.
  • Rate limit: 30 a minute per user and 60 a minute per IP address for this route, plus the shared 300 a minute. At most 60 KYB uploads a day per user.
  • Idempotency: Not supported. A retry stores another file; unattached uploads are deleted after a day.

Body (multipart) ​

NameTypeRequiredDescription
filefileYesThe document, PDF, JPG, PNG or WebP, at most 10 MB

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/enterprise/kyb/uploads \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "X-Enterprise-Account: $WORKSPACE_ID" \
  -F "[email protected];type=application/pdf"
js
import { openAsBlob } from 'node:fs';

const form = new FormData();
form.append('file', await openAsBlob('nib.pdf', { type: 'application/pdf' }), 'nib.pdf');
const res = await fetch('https://api.rekberpay.com/v1/enterprise/kyb/uploads', {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'X-Enterprise-Account': process.env.WORKSPACE_ID,
    },
    body: form,
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
with open("nib.pdf", "rb") as fh:
    resp = session.post(
        "https://api.rekberpay.com/v1/enterprise/kyb/uploads",
        headers={
            "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
            "X-Enterprise-Account": os.environ["WORKSPACE_ID"],
        },
        files={"file": ("nib.pdf", fh, "application/pdf")},
        timeout=60,
    )
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/kyb/uploads');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'X-Enterprise-Account: ' . getenv('WORKSPACE_ID'),
    ],
    CURLOPT_POSTFIELDS => ['file' => new CURLFile('nib.pdf', 'application/pdf', 'nib.pdf')],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

201 Created

json
{
    "success": true,
    "data": {
        "upload_id": "626500a8-25d8-41d6-b056-c533027fc736/1791911597675_98c93f7dbe3bc789d2226f40751b138a.pdf",
        "mime": "application/pdf",
        "size_bytes": 166,
        "sha256": "ada1c8a6c1878e7232df92a86849e8136f78db3ea28124d9c1c6b3cdc941b5ce"
    }
}

Errors ​

StatusCodeCause
400NO_FILENo single part named file
400TYPE_MISMATCHThe content, file name and Content-Type do not agree
400TYPE_NOT_ALLOWEDNot a PDF, JPG, PNG or WebP file (SVG, HTML, archives and Office files are refused)
400POLYGLOTThe file hides another format or markup
400PDF_ENCRYPTEDThe PDF is password protected
400PDF_ACTIVE_CONTENT, PDF_EMBEDDED_FILEThe PDF has scripts, actions or attached files
400IMAGE_TOO_LARGE, IMAGE_DECODE_FAILEDThe image is too large or could not be decoded
413FILE_TOO_LARGEOver 10 MB
429QUOTA_EXCEEDEDOver 60 KYB uploads in 24 hours
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Attach a document ​

POST/v1/enterprise/kyb/documents

Attaches one of your own unattached uploads to the draft as a document of doc_type. An upload can be attached once, only by the user who uploaded it. Person documents (ktp, passport) name the person with person_id. Uploading again for the same slot replaces the earlier document.

  • Auth: Dashboard session with X-CSRF-Token on writes. API keys get 403 KEY_NOT_ALLOWED: KYB is filled in by people, not integrations.
  • Role: admin or owner.
  • Rate limit: 30 a minute per user for this route, plus the shared 300 a minute. At most 40 documents per application.
  • Idempotency: Not needed: attaching the same upload to the same application again changes nothing.

Body (JSON) ​

NameTypeRequiredDescription
upload_idstringYesThe upload_id from Upload a document file
doc_typestringYesakta_pendirian, akta_perubahan, sk_kemenkumham, nib, npwp, ktp, passport, bank_proof, authority_letter, registration_certificate or tax_id
person_idUUIDFor ktp and passportA person from application.people

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/enterprise/kyb/documents \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "X-Enterprise-Account: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
      "upload_id": "0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf",
      "doc_type": "nib"
  }'
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/kyb/documents', {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'X-Enterprise-Account': process.env.WORKSPACE_ID,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        "upload_id": "0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf",
        "doc_type": "nib"
    }),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
    "https://api.rekberpay.com/v1/enterprise/kyb/documents",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
        "X-Enterprise-Account": os.environ["WORKSPACE_ID"],
    },
    json={
        "upload_id": "0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf",
        "doc_type": "nib"
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/kyb/documents');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'X-Enterprise-Account: ' . getenv('WORKSPACE_ID'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'upload_id' => '0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf',
        'doc_type' => 'nib',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

201 Created

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "account",
            "id": "8fc61a2b-dbf6-4070-a570-aaa2a6560d02",
            "name": "Sinar Laut MV6XWDGH",
            "kyb_status": "not_started",
            "is_sandbox": true,
            "account_manager": null
        },
        "application": {
            "id": "09c9e6db-ddb2-48b0-ad86-4122b24ebb8c",
            "version": 1,
            "status": "draft",
            "entity_type": "pt",
            "legal_name": "PT Sinar Laut Logistik MV6XWDGH",
            "country_code": "ID",
            "nib": "9120911597635",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Sinar Laut Logistik MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "e5bea0ba-c7ae-4387-bf5f-862d6c50fafa",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "99c7a474-8ca2-497b-acb6-3121a17041c7",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [
                {
                    "id": "47dc9b99-6a6d-4f12-9d4d-a6435ff4506d",
                    "doc_type": "akta_pendirian",
                    "person_id": null,
                    "original_name": "akta_pendirian.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 166,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.683Z"
                }
            ],
            "change_requests": [],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.683Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": false
            },
            "done": 3,
            "total": 4,
            "missing_documents": [
                {
                    "key": "sk_kemenkumham",
                    "type": "sk_kemenkumham",
                    "label": "SK Kemenkumham",
                    "hint": "The Ministry of Law approval for the deed.",
                    "required": true,
                    "person_id": null
                },
                {
                    "key": "nib",
                    "type": "nib",
                    "label": "NIB (OSS)",
                    "hint": "Your business registration number from OSS.",
                    "required": true,
                    "person_id": null
                }
            ],
            "complete": false
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 1,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
400INVALID_BODYUnknown doc_type, or a person document without person_id
404UPLOAD_NOT_FOUNDNo upload of yours with this ID, or it belongs to someone else
409UPLOAD_ALREADY_BOUNDThe upload is already attached to another application
404PERSON_NOT_FOUNDperson_id is not on this application
409DOCUMENT_LIMITThe application already has 40 documents
409APPLICATION_LOCKEDThe application is submitted and waiting for review
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Remove a document ​

DELETE/v1/enterprise/kyb/documents/:id

Removes a document from the draft. Documents of a submitted or decided version cannot be removed.

  • Auth: Dashboard session with X-CSRF-Token on writes. API keys get 403 KEY_NOT_ALLOWED: KYB is filled in by people, not integrations.
  • Role: admin or owner.
  • Rate limit: 30 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. A second call answers 404.

Path parameters ​

NameTypeDescription
idUUIDThe document id

Example request ​

bash
curl -X DELETE https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "X-Enterprise-Account: $WORKSPACE_ID"
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a', {
    method: 'DELETE',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'X-Enterprise-Account': process.env.WORKSPACE_ID,
    },
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.delete(
    "https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
        "X-Enterprise-Account": os.environ["WORKSPACE_ID"],
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'X-Enterprise-Account: ' . getenv('WORKSPACE_ID'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "account",
            "id": "8fc61a2b-dbf6-4070-a570-aaa2a6560d02",
            "name": "Sinar Laut MV6XWDGH",
            "kyb_status": "draft",
            "is_sandbox": true,
            "account_manager": null
        },
        "application": {
            "id": "61b95d77-3a11-4d25-ba85-27437db152ea",
            "version": 2,
            "status": "draft",
            "entity_type": "pt",
            "legal_name": "PT Sinar Laut Logistik MV6XWDGH",
            "country_code": "ID",
            "nib": "9120911597635",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Sinar Laut Logistik MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "7d0392ef-c14d-4836-9ea6-2746d6f98486",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "80e13305-314e-49c7-8068-c5666d60177e",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [
                {
                    "id": "c4682fbc-deb9-4978-8cc9-fc05b9d8e963",
                    "doc_type": "akta_pendirian",
                    "person_id": null,
                    "original_name": "akta_pendirian.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 166,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.843Z"
                },
                {
                    "id": "10a0d3f0-225e-48a8-bcf4-89abfbe14d9b",
                    "doc_type": "bank_proof",
                    "person_id": null,
                    "original_name": "bank_proof.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 162,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.843Z"
                }
            ],
            "change_requests": [
                {
                    "item": "doc:npwp",
                    "label": "NPWP badan",
                    "reason": "The NPWP photo is blurred."
                }
            ],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.856Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": false
            },
            "done": 3,
            "total": 4,
            "missing_documents": [
                {
                    "key": "npwp",
                    "type": "npwp",
                    "label": "NPWP badan",
                    "hint": "The company tax card or certificate.",
                    "required": true,
                    "person_id": null
                }
            ],
            "complete": false
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 2,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            },
            {
                "version": 1,
                "status": "changes_requested",
                "submitted_at": "2026-10-13T17:13:17.801Z",
                "decided_at": "2026-10-13T17:13:17.841Z",
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
404NOT_FOUNDNo document with this ID on the current draft
409APPLICATION_LOCKEDThe application is submitted and waiting for review
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

GET/v1/enterprise/kyb/documents/:id/url

A link to view one document, valid for 5 minutes and only for you: it is signed for your user ID, so open it with the same session. The file is re-checked against its SHA-256 on every read and sent with Cache-Control: private, no-store; PDFs download as attachments.

  • Auth: Dashboard session with X-CSRF-Token on writes. API keys get 403 KEY_NOT_ALLOWED: KYB is filled in by people, not integrations.
  • Role: finance, admin or owner.
  • Rate limit: 120 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. Reading has no side effects.

Path parameters ​

NameTypeDescription
idUUIDThe document id

Example request ​

bash
curl https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url \
  -b cookies.txt \
  -H "X-Enterprise-Account: $WORKSPACE_ID"
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url', {
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-Enterprise-Account': process.env.WORKSPACE_ID,
    },
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.get(
    "https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url",
    headers={
        "X-Enterprise-Account": os.environ["WORKSPACE_ID"],
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/kyb/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-Enterprise-Account: ' . getenv('WORKSPACE_ID'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "url": "/v1/kyb/files/86552ee4-5106-4524-9885-16bfd9ab7d80?exp=1791911897&sig=bTOf-ZzSc_9z_gB3y0d7WntW_0sRbPX8fn6xOdNd4ZA",
        "expires_at": "2026-10-13T17:18:17.000Z"
    }
}

Errors ​

StatusCodeCause
404NOT_FOUNDNo document with this ID on this workspace's applications
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Submit for review ​

POST/v1/enterprise/kyb/submit

Sends the draft to RekberPay for review. Every step must be complete: the company details, at least one director and one authorised signer with identity numbers, the bank account and every required document. The automatic checks run now (formats, duplicate NIB, NPWP or bank account on another workspace, screening, document content); they are shown to the reviewer and never reject on their own.

A verified workspace can update its details: the first save opens a new version and the workspace stays verified while RekberPay reviews the change. A suspended workspace cannot submit (409 SUSPENDED).

The application moves to submitted and the workspace's kyb_status to pending. We review in 1 to 3 business days; review.due_by is the end of that window.

  • Auth: Dashboard session with X-CSRF-Token on writes. API keys get 403 KEY_NOT_ALLOWED: KYB is filled in by people, not integrations.
  • Role: admin or owner.
  • Rate limit: 10 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Send an Idempotency-Key header (UUID v4). A retry with the same key returns the first answer with Idempotent-Replay: true.

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/enterprise/kyb/submit \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "X-Enterprise-Account: $WORKSPACE_ID" \
  -H "Idempotency-Key: 99999995-9999-4999-8999-999999999999" \
  -H "Content-Type: application/json" \
  -d '{}'
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/kyb/submit', {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'X-Enterprise-Account': process.env.WORKSPACE_ID,
        'Idempotency-Key': '99999995-9999-4999-8999-999999999999',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({}),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
    "https://api.rekberpay.com/v1/enterprise/kyb/submit",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
        "X-Enterprise-Account": os.environ["WORKSPACE_ID"],
        "Idempotency-Key": "99999995-9999-4999-8999-999999999999",
    },
    json={},
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/kyb/submit');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'X-Enterprise-Account: ' . getenv('WORKSPACE_ID'),
        'Idempotency-Key: 99999995-9999-4999-8999-999999999999',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(new stdClass()),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "account",
            "id": "8fc61a2b-dbf6-4070-a570-aaa2a6560d02",
            "name": "Sinar Laut MV6XWDGH",
            "kyb_status": "pending",
            "is_sandbox": true,
            "account_manager": null
        },
        "application": {
            "id": "09c9e6db-ddb2-48b0-ad86-4122b24ebb8c",
            "version": 1,
            "status": "submitted",
            "entity_type": "pt",
            "legal_name": "PT Sinar Laut Logistik MV6XWDGH",
            "country_code": "ID",
            "nib": "9120911597635",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Sinar Laut Logistik MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "e5bea0ba-c7ae-4387-bf5f-862d6c50fafa",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "99c7a474-8ca2-497b-acb6-3121a17041c7",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [
                {
                    "id": "47dc9b99-6a6d-4f12-9d4d-a6435ff4506d",
                    "doc_type": "akta_pendirian",
                    "person_id": null,
                    "original_name": "akta_pendirian.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 166,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.683Z"
                },
                {
                    "id": "da546100-4ae6-4f27-ad36-e8f796fc7e8e",
                    "doc_type": "bank_proof",
                    "person_id": null,
                    "original_name": "bank_proof.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 162,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.730Z"
                }
            ],
            "change_requests": [],
            "submitted_at": "2026-10-13T17:13:17.801Z",
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.801Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": true
            },
            "done": 4,
            "total": 4,
            "missing_documents": [],
            "complete": true
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 1,
                "status": "submitted",
                "submitted_at": "2026-10-13T17:13:17.801Z",
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": "2026-10-18T17:13:17.801Z"
        },
        "can_edit": false
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
422INCOMPLETEA step is not complete. error.details lists the missing fields and documents
409APPLICATION_LOCKEDAlready submitted
409SUSPENDEDThe workspace is suspended. Contact RekberPay
409CONCURRENT_MODIFICATIONThe application changed while submitting. Reload and try again
409IDEMPOTENCY_KEY_IN_FLIGHTThe first call with this key is still running
422IDEMPOTENCY_KEY_CONFLICTThe key was used with another body
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

POST/v1/enterprise/counterparties/:id/kyb-invite

Creates a signed link that lets the counterparty verify its company with the same four steps. The link is valid for 14 days. The first signed-in RekberPay user who opens it becomes its only user. RekberPay reviews it in the same queue, and the decision sets the counterparty's kyb_status. Creating a new link revokes the earlier ones for that counterparty. Send the url to your contact yourself.

  • Auth: Dashboard session with X-CSRF-Token on writes. API keys get 403 KEY_NOT_ALLOWED: KYB is filled in by people, not integrations.
  • Role: admin or owner.
  • Rate limit: 10 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not supported, so the link never sits in a replay cache. A retry creates a new link and revokes the earlier one.

Path parameters ​

NameTypeDescription
idUUIDThe counterparty id

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/enterprise/counterparties/cccccccc-cccc-4ccc-8ccc-cccccccccccc/kyb-invite \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "X-Enterprise-Account: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{}'
js
const res = await fetch('https://api.rekberpay.com/v1/enterprise/counterparties/cccccccc-cccc-4ccc-8ccc-cccccccccccc/kyb-invite', {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'X-Enterprise-Account': process.env.WORKSPACE_ID,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({}),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
    "https://api.rekberpay.com/v1/enterprise/counterparties/cccccccc-cccc-4ccc-8ccc-cccccccccccc/kyb-invite",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
        "X-Enterprise-Account": os.environ["WORKSPACE_ID"],
    },
    json={},
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/enterprise/counterparties/cccccccc-cccc-4ccc-8ccc-cccccccccccc/kyb-invite');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'X-Enterprise-Account: ' . getenv('WORKSPACE_ID'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(new stdClass()),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

201 Created

json
{
    "success": true,
    "data": {
        "url": "https://rekberpay.com/enterprise/verify/65732574-5893-47cc-aade-00e416d1b649.1793121197.30B15AStFrVbMj3HGht18kaOPZ8_P_cCA47q7NWnHVI",
        "token": "65732574-5893-47cc-aade-00e416d1b649.1793121197.30B15AStFrVbMj3HGht18kaOPZ8_P_cCA47q7NWnHVI",
        "expires_at": "2026-10-27T17:13:17.000Z"
    }
}

Errors ​

StatusCodeCause
404NOT_FOUNDNo counterparty with this ID in the workspace
409ALREADY_VERIFIEDThe counterparty is already verified
400INVALID_ACCOUNTX-Enterprise-Account is not a UUID
403NO_WORKSPACEYou are not an active member of that workspace
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

GET/v1/kyb/invite/:token

The counterparty side. Returns the same full view as Get the KYB application, for the counterparty's application. The first signed-in user to open a link claims it; anyone else gets 403 INVITE_CLAIMED. No workspace is needed.

  • Auth: Dashboard session of any signed-in RekberPay user. API keys get 403 KEY_NOT_ALLOWED.
  • Rate limit: 120 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. Opening twice is the same as once.

Path parameters ​

NameTypeDescription
tokenstringThe token at the end of the link

Example request ​

bash
curl https://api.rekberpay.com/v1/kyb/invite/$KYB_INVITE_TOKEN \
  -b cookies.txt
js
const res = await fetch(`https://api.rekberpay.com/v1/kyb/invite/${process.env.KYB_INVITE_TOKEN}`, {
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
    },
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.get(
    f"https://api.rekberpay.com/v1/kyb/invite/{os.environ['KYB_INVITE_TOKEN']}",
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/kyb/invite/' . getenv('KYB_INVITE_TOKEN'));
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "counterparty",
            "id": "6088d36c-5793-4f82-a024-34f064971d12",
            "name": "PT Mitra Kargo MV6XWDGH",
            "kyb_status": "not_started",
            "invited_by": "Sinar Laut MV6XWDGH"
        },
        "application": {
            "id": "78d3f2d7-1eed-4434-a86a-8be3941965fe",
            "version": 1,
            "status": "draft",
            "entity_type": null,
            "legal_name": "PT Mitra Kargo MV6XWDGH",
            "country_code": "ID",
            "nib": null,
            "npwp": null,
            "address": null,
            "industry": null,
            "monthly_volume": null,
            "website": null,
            "bank": {
                "bank_name": null,
                "bank_account_holder": null,
                "account_number_last4": null,
                "has_account_number": false
            },
            "people": [],
            "documents": [],
            "change_requests": [],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.950Z"
        },
        "progress": {
            "steps": {
                "company": false,
                "people": false,
                "bank": false,
                "documents": false
            },
            "done": 0,
            "total": 4,
            "missing_documents": [],
            "complete": false
        },
        "slots": [],
        "history": [
            {
                "version": 1,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Errors ​

StatusCodeCause
404INVITE_INVALIDThe token is malformed, forged or revoked
410INVITE_EXPIREDThe link is older than 14 days. Ask for a new one
403INVITE_CLAIMEDAnother user already opened this link
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Save a counterparty draft ​

PATCH/v1/kyb/invite/:token

The same body and rules as Save the draft, for the counterparty's application.

  • Auth: Dashboard session of the user who opened the link first.
  • Rate limit: 120 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. Saving the same body twice leaves the same draft.

Path parameters ​

NameTypeDescription
tokenstringThe token at the end of the link

Example request ​

bash
curl -X PATCH https://api.rekberpay.com/v1/kyb/invite/$KYB_INVITE_TOKEN \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
      "company": {
          "legal_name": "PT Mitra Kargo Nusantara",
          "entity_type": "pt",
          "nib": "9120007654321"
      }
  }'
js
const res = await fetch(`https://api.rekberpay.com/v1/kyb/invite/${process.env.KYB_INVITE_TOKEN}`, {
    method: 'PATCH',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        "company": {
            "legal_name": "PT Mitra Kargo Nusantara",
            "entity_type": "pt",
            "nib": "9120007654321"
        }
    }),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.patch(
    f"https://api.rekberpay.com/v1/kyb/invite/{os.environ['KYB_INVITE_TOKEN']}",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
    },
    json={
        "company": {
            "legal_name": "PT Mitra Kargo Nusantara",
            "entity_type": "pt",
            "nib": "9120007654321"
        }
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/kyb/invite/' . getenv('KYB_INVITE_TOKEN'));
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'company' => [
            'legal_name' => 'PT Mitra Kargo Nusantara',
            'entity_type' => 'pt',
            'nib' => '9120007654321',
        ],
    ]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "counterparty",
            "id": "6088d36c-5793-4f82-a024-34f064971d12",
            "name": "PT Mitra Kargo MV6XWDGH",
            "kyb_status": "not_started",
            "invited_by": "Sinar Laut MV6XWDGH"
        },
        "application": {
            "id": "78d3f2d7-1eed-4434-a86a-8be3941965fe",
            "version": 1,
            "status": "draft",
            "entity_type": "pt",
            "legal_name": "PT Mitra Kargo MV6XWDGH",
            "country_code": "ID",
            "nib": "9121911597966",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Mitra Kargo MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "c5e85da2-a7c2-4f92-b910-e212afa1e1a0",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "1ee2a98e-80c7-4f69-979b-8971e56a36b2",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [],
            "change_requests": [],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.971Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": false
            },
            "done": 3,
            "total": 4,
            "missing_documents": [
                {
                    "key": "akta_pendirian",
                    "type": "akta_pendirian",
                    "label": "Akta pendirian",
                    "hint": "The deed of establishment.",
                    "required": true,
                    "person_id": null
                },
                {
                    "key": "sk_kemenkumham",
                    "type": "sk_kemenkumham",
                    "label": "SK Kemenkumham",
                    "hint": "The Ministry of Law approval for the deed.",
                    "required": true,
                    "person_id": null
                }
            ],
            "complete": false
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 1,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
400INVALID_BODYA field has the wrong format, see error.details
404INVITE_INVALIDThe token is malformed, forged or revoked
410INVITE_EXPIREDThe link has expired
403INVITE_CLAIMEDAnother user already opened this link
409APPLICATION_LOCKEDThe application is submitted and waiting for review
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Upload a counterparty document file ​

POST/v1/kyb/invite/:token/uploads

The same checks and answer as Upload a document file.

  • Auth: Dashboard session of the user who opened the link first.
  • Rate limit: 30 a minute per user and 60 a minute per IP address for this route, plus the shared 300 a minute.
  • Idempotency: Not supported. A retry stores another file; unattached uploads are deleted after a day.

Path parameters ​

NameTypeDescription
tokenstringThe token at the end of the link

Body (multipart) ​

NameTypeRequiredDescription
filefileYesThe document, PDF, JPG, PNG or WebP, at most 10 MB

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/kyb/invite/$KYB_INVITE_TOKEN/uploads \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -F "[email protected];type=application/pdf"
js
import { openAsBlob } from 'node:fs';

const form = new FormData();
form.append('file', await openAsBlob('nib.pdf', { type: 'application/pdf' }), 'nib.pdf');
const res = await fetch(`https://api.rekberpay.com/v1/kyb/invite/${process.env.KYB_INVITE_TOKEN}/uploads`, {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
    },
    body: form,
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
with open("nib.pdf", "rb") as fh:
    resp = session.post(
        f"https://api.rekberpay.com/v1/kyb/invite/{os.environ['KYB_INVITE_TOKEN']}/uploads",
        headers={
            "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
        },
        files={"file": ("nib.pdf", fh, "application/pdf")},
        timeout=60,
    )
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/kyb/invite/' . getenv('KYB_INVITE_TOKEN') . '/uploads');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
    ],
    CURLOPT_POSTFIELDS => ['file' => new CURLFile('nib.pdf', 'application/pdf', 'nib.pdf')],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

201 Created

json
{
    "success": true,
    "data": {
        "upload_id": "8243ffd8-3532-43fb-8063-053a639603dc/1791911597978_17b5bc5abd2ec7faa21c128bff20629a.pdf",
        "mime": "application/pdf",
        "size_bytes": 166,
        "sha256": "ada1c8a6c1878e7232df92a86849e8136f78db3ea28124d9c1c6b3cdc941b5ce"
    }
}

Errors ​

StatusCodeCause
400TYPE_MISMATCH, TYPE_NOT_ALLOWED, POLYGLOT, PDF_ENCRYPTED, PDF_ACTIVE_CONTENTThe file was refused, see Upload a document file
413FILE_TOO_LARGEOver 10 MB
404INVITE_INVALIDThe token is malformed, forged or revoked
403INVITE_CLAIMEDAnother user already opened this link
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Attach a counterparty document ​

POST/v1/kyb/invite/:token/documents

The same body and rules as Attach a document.

  • Auth: Dashboard session of the user who opened the link first.
  • Rate limit: 30 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed: an upload can only be attached once.

Path parameters ​

NameTypeDescription
tokenstringThe token at the end of the link

Body (JSON) ​

NameTypeRequiredDescription
upload_idstringYesYour own unattached upload
doc_typestringYesSee Attach a document
person_idUUIDFor ktp and passportA person from application.people

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/kyb/invite/$KYB_INVITE_TOKEN/documents \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
      "upload_id": "0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf",
      "doc_type": "bank_proof"
  }'
js
const res = await fetch(`https://api.rekberpay.com/v1/kyb/invite/${process.env.KYB_INVITE_TOKEN}/documents`, {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        "upload_id": "0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf",
        "doc_type": "bank_proof"
    }),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
    f"https://api.rekberpay.com/v1/kyb/invite/{os.environ['KYB_INVITE_TOKEN']}/documents",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
    },
    json={
        "upload_id": "0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf",
        "doc_type": "bank_proof"
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/kyb/invite/' . getenv('KYB_INVITE_TOKEN') . '/documents');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'upload_id' => '0b6c8a52-1f0e-4d4a-9a55-6e8c2f2b1c11/1760367000123_4f9c2d7e8a1b3c5d6e7f8091a2b3c4d5.pdf',
        'doc_type' => 'bank_proof',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

201 Created

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "counterparty",
            "id": "6088d36c-5793-4f82-a024-34f064971d12",
            "name": "PT Mitra Kargo MV6XWDGH",
            "kyb_status": "not_started",
            "invited_by": "Sinar Laut MV6XWDGH"
        },
        "application": {
            "id": "78d3f2d7-1eed-4434-a86a-8be3941965fe",
            "version": 1,
            "status": "draft",
            "entity_type": "pt",
            "legal_name": "PT Mitra Kargo MV6XWDGH",
            "country_code": "ID",
            "nib": "9121911597966",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Mitra Kargo MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "c5e85da2-a7c2-4f92-b910-e212afa1e1a0",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "1ee2a98e-80c7-4f69-979b-8971e56a36b2",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [
                {
                    "id": "2a370bb3-76c2-4416-afc8-ef0d4d621a1b",
                    "doc_type": "akta_pendirian",
                    "person_id": null,
                    "original_name": "akta_pendirian.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 166,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.982Z"
                }
            ],
            "change_requests": [],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:17.982Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": false
            },
            "done": 3,
            "total": 4,
            "missing_documents": [
                {
                    "key": "sk_kemenkumham",
                    "type": "sk_kemenkumham",
                    "label": "SK Kemenkumham",
                    "hint": "The Ministry of Law approval for the deed.",
                    "required": true,
                    "person_id": null
                },
                {
                    "key": "nib",
                    "type": "nib",
                    "label": "NIB (OSS)",
                    "hint": "Your business registration number from OSS.",
                    "required": true,
                    "person_id": null
                }
            ],
            "complete": false
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 1,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
404UPLOAD_NOT_FOUNDNo unattached upload of yours with this ID
404INVITE_INVALIDThe token is malformed, forged or revoked
409APPLICATION_LOCKEDThe application is submitted and waiting for review
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Remove a counterparty document ​

DELETE/v1/kyb/invite/:token/documents/:id

Removes a document from the counterparty's draft.

  • Auth: Dashboard session of the user who opened the link first.
  • Rate limit: 30 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. A second call answers 404.

Path parameters ​

NameTypeDescription
tokenstringThe token at the end of the link
idUUIDThe document id

Example request ​

bash
curl -X DELETE https://api.rekberpay.com/v1/kyb/invite/$KYB_INVITE_TOKEN/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN"
js
const res = await fetch(`https://api.rekberpay.com/v1/kyb/invite/${process.env.KYB_INVITE_TOKEN}/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a`, {
    method: 'DELETE',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
    },
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.delete(
    f"https://api.rekberpay.com/v1/kyb/invite/{os.environ['KYB_INVITE_TOKEN']}/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
    },
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/kyb/invite/' . getenv('KYB_INVITE_TOKEN') . '/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
    ],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "counterparty",
            "id": "6088d36c-5793-4f82-a024-34f064971d12",
            "name": "PT Mitra Kargo MV6XWDGH",
            "kyb_status": "not_started",
            "invited_by": "Sinar Laut MV6XWDGH"
        },
        "application": {
            "id": "78d3f2d7-1eed-4434-a86a-8be3941965fe",
            "version": 1,
            "status": "draft",
            "entity_type": "pt",
            "legal_name": "PT Mitra Kargo MV6XWDGH",
            "country_code": "ID",
            "nib": "9121911597966",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Mitra Kargo MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "c5e85da2-a7c2-4f92-b910-e212afa1e1a0",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "1ee2a98e-80c7-4f69-979b-8971e56a36b2",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [
                {
                    "id": "2a370bb3-76c2-4416-afc8-ef0d4d621a1b",
                    "doc_type": "akta_pendirian",
                    "person_id": null,
                    "original_name": "akta_pendirian.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 166,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.982Z"
                },
                {
                    "id": "c3825c07-d037-4e0d-9cc3-afe62941a0c3",
                    "doc_type": "ktp",
                    "person_id": "c5e85da2-a7c2-4f92-b910-e212afa1e1a0",
                    "original_name": "ktp.jpg",
                    "mime": "image/jpeg",
                    "size_bytes": 1769,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:18.029Z"
                }
            ],
            "change_requests": [],
            "submitted_at": null,
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:18.052Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": false
            },
            "done": 3,
            "total": 4,
            "missing_documents": [
                {
                    "key": "bank_proof",
                    "type": "bank_proof",
                    "label": "Proof of bank account",
                    "hint": "A statement cover or a bank letter showing the account holder name.",
                    "required": true,
                    "person_id": null
                }
            ],
            "complete": false
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 1,
                "status": "draft",
                "submitted_at": null,
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": null
        },
        "can_edit": true
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
404NOT_FOUNDNo document with this ID on the current draft
409APPLICATION_LOCKEDThe application is submitted
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

GET/v1/kyb/invite/:token/documents/:id/url

A 5 minute link to one of the counterparty's documents, signed for you. See Get a document link.

  • Auth: Dashboard session of the user who opened the link first.
  • Rate limit: 120 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Not needed. Reading has no side effects.

Path parameters ​

NameTypeDescription
tokenstringThe token at the end of the link
idUUIDThe document id

Example request ​

bash
curl https://api.rekberpay.com/v1/kyb/invite/$KYB_INVITE_TOKEN/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url \
  -b cookies.txt
js
const res = await fetch(`https://api.rekberpay.com/v1/kyb/invite/${process.env.KYB_INVITE_TOKEN}/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url`, {
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
    },
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.get(
    f"https://api.rekberpay.com/v1/kyb/invite/{os.environ['KYB_INVITE_TOKEN']}/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url",
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/kyb/invite/' . getenv('KYB_INVITE_TOKEN') . '/documents/d0c00001-d0c0-4d0c-8d0c-d0c00000000a/url');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "url": "/v1/kyb/files/4b329f64-637a-4cea-8a39-323c31b3c5c0?exp=1791911898&sig=N4cioEqVQd2AjhEgQJXTDt3oVzg9EolhkCiZRXXvGWk",
        "expires_at": "2026-10-13T17:18:18.000Z"
    }
}

Errors ​

StatusCodeCause
404NOT_FOUNDNo document with this ID on this application
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Submit a counterparty application ​

POST/v1/kyb/invite/:token/submit

The same checks as Submit for review. The counterparty's kyb_status moves to pending, and the workspace that sent the link sees the decision on the counterparty.

  • Auth: Dashboard session of the user who opened the link first.
  • Rate limit: 10 a minute per user for this route, plus the shared 300 a minute.
  • Idempotency: Send an Idempotency-Key header (UUID v4). A retry with the same key returns the first answer with Idempotent-Replay: true.

Path parameters ​

NameTypeDescription
tokenstringThe token at the end of the link

Example request ​

bash
curl -X POST https://api.rekberpay.com/v1/kyb/invite/$KYB_INVITE_TOKEN/submit \
  -b cookies.txt \
  -H "X-CSRF-Token: $CSRF_TOKEN" \
  -H "Idempotency-Key: 99999995-9999-4999-8999-999999999999" \
  -H "Content-Type: application/json" \
  -d '{}'
js
const res = await fetch(`https://api.rekberpay.com/v1/kyb/invite/${process.env.KYB_INVITE_TOKEN}/submit`, {
    method: 'POST',
    headers: {
        Cookie: process.env.REKBERPAY_SESSION_COOKIE, // the session cookie from POST /v1/auth/login
        'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
        'Idempotency-Key': '99999995-9999-4999-8999-999999999999',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({}),
});
const data = await res.json();
python
import os

import requests

session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
    f"https://api.rekberpay.com/v1/kyb/invite/{os.environ['KYB_INVITE_TOKEN']}/submit",
    headers={
        "X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
        "Idempotency-Key": "99999995-9999-4999-8999-999999999999",
    },
    json={},
    timeout=30,
)
print(resp.status_code, resp.json())
php
<?php

$ch = curl_init('https://api.rekberpay.com/v1/kyb/invite/' . getenv('KYB_INVITE_TOKEN') . '/submit');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_HTTPHEADER => [
        'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
        'Idempotency-Key: 99999995-9999-4999-8999-999999999999',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(new stdClass()),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

Example response ​

200 OK

json
{
    "success": true,
    "data": {
        "view": "full",
        "subject": {
            "type": "counterparty",
            "id": "6088d36c-5793-4f82-a024-34f064971d12",
            "name": "PT Mitra Kargo MV6XWDGH",
            "kyb_status": "pending",
            "invited_by": "Sinar Laut MV6XWDGH"
        },
        "application": {
            "id": "78d3f2d7-1eed-4434-a86a-8be3941965fe",
            "version": 1,
            "status": "submitted",
            "entity_type": "pt",
            "legal_name": "PT Mitra Kargo MV6XWDGH",
            "country_code": "ID",
            "nib": "9121911597966",
            "npwp": "012345678901000",
            "address": "Jl. Pelabuhan Raya 12, Tanjung Priok, Jakarta Utara 14310",
            "industry": "Logistics",
            "monthly_volume": "1b_10b",
            "website": "https://sinarlaut.example",
            "bank": {
                "bank_name": "BCA",
                "bank_account_holder": "PT Mitra Kargo MV6XWDGH",
                "account_number_last4": "2219",
                "has_account_number": true
            },
            "people": [
                {
                    "id": "c5e85da2-a7c2-4f92-b910-e212afa1e1a0",
                    "full_name": "Ayu Pratiwi",
                    "position": "President Director",
                    "roles": [
                        "director",
                        "signer"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0001",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 60
                },
                {
                    "id": "1ee2a98e-80c7-4f69-979b-8971e56a36b2",
                    "full_name": "Bima Santoso",
                    "position": "Director",
                    "roles": [
                        "director",
                        "beneficial_owner"
                    ],
                    "id_type": "nik",
                    "id_number_last4": "0002",
                    "has_id_number": true,
                    "nationality": "ID",
                    "ownership_pct": 40
                }
            ],
            "documents": [
                {
                    "id": "2a370bb3-76c2-4416-afc8-ef0d4d621a1b",
                    "doc_type": "akta_pendirian",
                    "person_id": null,
                    "original_name": "akta_pendirian.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 166,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:17.982Z"
                },
                {
                    "id": "c5d75bc2-afd2-4e8c-9521-c37be010749a",
                    "doc_type": "bank_proof",
                    "person_id": null,
                    "original_name": "bank.pdf",
                    "mime": "application/pdf",
                    "size_bytes": 156,
                    "status": "uploaded",
                    "reviewer_note": null,
                    "created_at": "2026-10-13T17:13:18.060Z"
                }
            ],
            "change_requests": [],
            "submitted_at": "2026-10-13T17:13:18.067Z",
            "decided_at": null,
            "decision_reason": null,
            "risk_tier_assigned": null,
            "updated_at": "2026-10-13T17:13:18.067Z"
        },
        "progress": {
            "steps": {
                "company": true,
                "people": true,
                "bank": true,
                "documents": true
            },
            "done": 4,
            "total": 4,
            "missing_documents": [],
            "complete": true
        },
        "slots": [
            {
                "key": "akta_pendirian",
                "type": "akta_pendirian",
                "label": "Akta pendirian",
                "hint": "The deed of establishment.",
                "required": true,
                "person_id": null
            },
            {
                "key": "akta_perubahan",
                "type": "akta_perubahan",
                "label": "Latest akta perubahan",
                "hint": "The most recent amendment deed, if the company has one.",
                "required": false,
                "person_id": null
            }
        ],
        "history": [
            {
                "version": 1,
                "status": "submitted",
                "submitted_at": "2026-10-13T17:13:18.067Z",
                "decided_at": null,
                "decision_reason": null
            }
        ],
        "review": {
            "min_days": 1,
            "max_days": 3,
            "due_by": "2026-10-18T17:13:18.067Z"
        },
        "can_edit": false
    }
}

Lists are cut to the first 2 items here.

Errors ​

StatusCodeCause
422INCOMPLETEA step is not complete, see error.details
409APPLICATION_LOCKEDAlready submitted
404INVITE_INVALIDThe token is malformed, forged or revoked
401UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKENNo session or key, the session expired, or the key is wrong or revoked
403CSRF_FAILEDSession call without the matching X-CSRF-Token header
429RATE_LIMITEDOver the rate limit. Wait for Retry-After seconds

Escrow, payment services and B2B deals for Indonesian businesses.