Skip to main content

Client API

Client management operations including client creation with admin users, instance management, and organizational structure. Handles PSP assignment, eKYC integration, Xendit customer creation for Indonesia, and email notifications.

Create Client with Admin

POST/api/clients/create_with_admin

Create Client with Admin

Create a new client organization with an admin user. Automatically generates client code (CL-YYYYMM-XXXX format), assigns PSP based on country, creates admin user with secure password, and sends welcome email. Includes Xendit customer creation for Indonesia clients. Uses database transaction safety.

Parameters

emailstringrequired

Admin email address (must be unique)

client_aliasstringrequired

Client organization name/alias

client_typestringrequired

Type of client organization (CORPORATE, STARTUP, etc.)

country_codestringrequired

Country code for PSP assignment and eKYC (2-letter ISO code)

phonestringrequired

Contact phone number with country code

client_statusstring

Client status (default: 'PENDING')

Request Body

{
  "email": "admin@company.com",
  "client_alias": "Tech Company Ltd",
  "client_type": "CORPORATE",
  "country_code": "ID",
  "phone": "+628123456789",
  "client_status": "PENDING"
}

Response

201Client and admin created successfully (Indonesia with Xendit)
{
  "message": "Client & Admin successfully created! Admin must complete KYC before being able to use the account.",
  "client": {
    "client_id": 1,
    "client_code": "CL-202401-0001",
    "email": "admin@company.com",
    "client_alias": "Tech Company Ltd",
    "client_type": "CORPORATE",
    "client_status": "PENDING",
    "ekyc_status": "PENDING",
    "country_code": "ID",
    "psp_id": 11,
    "phone": "+628123456789"
  },
  "admin_user": {
    "user_id": 123,
    "client_id": 1,
    "username": "Tech Company Ltd",
    "email": "admin@company.com",
    "phone": "+628123456789",
    "role": "admin",
    "user_status": "ACTIVE",
    "ekyc_status": "PENDING"
  },
  "ekyc_status": "PENDING",
  "xendit_integration": {
    "psp_provider": "XENDIT",
    "business_customer": {
      "status": "success",
      "customer_id": "cust_business_1234567890",
      "customer_type": "BUSINESS"
    },
    "admin_customer": {
      "status": "success",
      "customer_id": "cust_individual_0987654321",
      "customer_type": "INDIVIDUAL"
    }
  }
}
400Validation error
{
  "error": "Email, Name, Type, Country and Mobile Number are required!"
}
409Email already in use
{
  "error": "Email is already in use by another client."
}
500Server error
{
  "error": "Failed to create Client",
  "details": "Database transaction failed"
}
201_non_idClient and admin created successfully (non-Indonesia)
{
  "message": "Client & Admin successfully created! Admin must complete KYC before being able to use the account.",
  "client": {
    "client_id": 2,
    "client_code": "CL-202401-0002",
    "email": "admin@sgcompany.com",
    "client_alias": "Singapore Tech Ltd",
    "client_type": "CORPORATE",
    "client_status": "PENDING",
    "ekyc_status": "PENDING",
    "country_code": "SG",
    "psp_id": 2,
    "phone": "+6591234567"
  },
  "admin_user": {
    "user_id": 124,
    "client_id": 2,
    "username": "Singapore Tech Ltd",
    "email": "admin@sgcompany.com",
    "phone": "+6591234567",
    "role": "admin",
    "user_status": "ACTIVE",
    "ekyc_status": "PENDING"
  },
  "ekyc_status": "PENDING"
}
400_no_pspNo PSP available for country
{
  "error": "No PSP available for the selected country."
}
400_no_fiat_pspNo FIAT PSP available for country
{
  "error": "There is no FIAT_PSP PSP available for that country."
}
curl -X POST https://api.brdz.link/api/clients/create_with_admin \
-H "Content-Type: application/json" \
-d '{
  "email": "admin@company.com",
  "client_alias": "Tech Company Ltd",
  "client_type": "CORPORATE",
  "country_code": "ID",
  "phone": "+628123456789"
}'

Get All Clients

GET/api/clients

Get All Clients

Retrieve list of all clients in the system. Admin access required. Returns clients ordered by creation date (newest first) with PSP and contact information.

Response

200Clients retrieved successfully
[
  {
    "client_id": 1,
    "client_code": "CL-202401-0001",
    "email": "admin@company.com",
    "client_alias": "Tech Company Ltd",
    "client_type": "CORPORATE",
    "client_status": "ACTIVE",
    "ekyc_status": "APPROVED",
    "country_code": "ID",
    "psp_id": 11,
    "phone": "+628123456789",
    "created": "2024-01-15T10:30:00Z",
    "updated": "2024-01-15T11:45:00Z"
  },
  {
    "client_id": 2,
    "client_code": "CL-202401-0002",
    "email": "admin@startup.com",
    "client_alias": "Startup Inc",
    "client_type": "STARTUP",
    "client_status": "PENDING",
    "ekyc_status": "PENDING",
    "country_code": "SG",
    "psp_id": 2,
    "phone": "+6591234567",
    "created": "2024-01-14T09:15:00Z",
    "updated": "2024-01-14T09:15:00Z"
  },
  {
    "client_id": 3,
    "client_code": "CL-202401-0003",
    "email": "admin@usacorp.com",
    "client_alias": "USA Corporation",
    "client_type": "CORPORATE",
    "client_status": "ACTIVE",
    "ekyc_status": "APPROVED",
    "country_code": "US",
    "psp_id": 4,
    "phone": "+15551234567",
    "created": "2024-01-13T14:20:00Z",
    "updated": "2024-01-13T16:30:00Z"
  }
]
500Server error
{
  "error": "Failed to fetch clients",
  "details": "Database connection failed"
}
curl -X GET https://api.brdz.link/api/clients \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY"

Get My Instances

GET/api/clients/my-instances

Get My Instances

Retrieve instances belonging to the logged-in admin's client. Returns instance list with client information joined from database including eKYC and client code information.

Response

200Instances retrieved successfully
{
  "instances": [
    {
      "instance_id": 1,
      "client_id": 1,
      "instance_name": "Production API",
      "client_alias": "Prod Environment",
      "instance_status": "ACTIVE",
      "ekyc_status": "APPROVED",
      "client_code": "CL-202401-0001",
      "country_code": "ID"
    },
    {
      "instance_id": 2,
      "client_id": 1,
      "instance_name": "Staging API",
      "client_alias": "Test Environment",
      "instance_status": "ACTIVE",
      "ekyc_status": "APPROVED",
      "client_code": "CL-202401-0001",
      "country_code": "ID"
    },
    {
      "instance_id": 3,
      "client_id": 1,
      "instance_name": "Development API",
      "client_alias": null,
      "instance_status": "ACTIVE",
      "ekyc_status": "APPROVED",
      "client_code": "CL-202401-0001",
      "country_code": "ID"
    }
  ]
}
404Client not found for user
{
  "error": "Client not found for this user."
}
500Server error
{
  "error": "Failed to fetch instance:",
  "details": "Database query failed"
}
curl -X GET https://api.brdz.link/api/clients/my-instances \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY"

Create Instance

POST/api/clients/create-instance

Create Instance

Create a new instance for the logged-in admin's client. Instance belongs to the client associated with the authenticated admin user. Requires admin authentication and valid client association.

Parameters

instance_namestringrequired

Name for the new instance (unique within client)

Request Body

{
  "instance_name": "Development API"
}

Response

201Instance created successfully
{
  "message": "Instance created successfully",
  "instance": {
    "instance_id": 4,
    "client_id": 1,
    "instance_name": "Development API",
    "client_alias": null,
    "instance_status": "ACTIVE",
    "created_at": "2024-01-15T12:00:00Z",
    "updated_at": "2024-01-15T12:00:00Z"
  }
}
400Instance name required
{
  "error": "Instance name is required"
}
403Client ID not found for user
{
  "error": "Client ID not found"
}
500Server error
{
  "error": "Internal server error"
}
curl -X POST https://api.brdz.link/api/clients/create-instance \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"instance_name": "Development API"}'

Update Instance Alias

PUT/api/clients/{instance_id}/update-alias

Update Instance Alias

Update the display alias for an instance. Only the admin of the client that owns the instance can perform this update. Alias is optional display name for better identification.

Parameters

instance_idnumberrequired

Instance ID to update (path parameter)

aliasstringrequired

New alias/display name for the instance

Request Body

{
  "alias": "Production Environment v2"
}

Response

200Alias updated successfully
{
  "message": "✅ The alias was updated successfully"
}
400Missing required fields
{
  "error": "Alias ​​and Instance ID are required."
}
403Access denied - instance not owned by user's client
{
  "error": "Access denied. The instance is not yours."
}
404Client not found for authenticated user
{
  "error": "Client not found"
}
500Server error
{
  "error": "Failed to update alias",
  "details": "Database update failed"
}
curl -X PUT https://api.brdz.link/api/clients/1/update-alias \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"alias": "Production Environment v2"}'

Delete Instance

DELETE/api/clients/clients/{instance_id}

Delete Instance

Delete an instance by ID. Only the admin of the client that owns the instance can perform this deletion. Permanent deletion from database - cannot be undone.

Parameters

instance_idnumberrequired

Instance ID to delete (path parameter)

Response

200Instance deleted successfully
{
  "message": "Instance deleted successfully"
}
403User not found or not linked to client
{
  "error": "User not found or not linked to any client"
}
404Instance not found or access denied
{
  "error": "Instance not found or does not belong to your client"
}
500Server error
{
  "error": "Failed to delete instance",
  "details": "Database deletion failed"
}
curl -X DELETE https://api.brdz.link/api/clients/clients/1 \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY"

Client Creation Process

Automated Client Code Generation

Client codes follow the format: CL-YYYYMM-XXXX

const generateClientCode = async () => {
const yearMonth = new Date().toISOString().slice(0, 7).replace('-', '');
const prefix = `CL-${yearMonth}-`;

const result = await db.query(
`SELECT MAX(SUBSTRING(client_code FROM 11 FOR 4))::INTEGER AS max_seq
FROM clients
WHERE client_code LIKE $1`,
[`${prefix}%`]
);

const nextSeq = (result.rows[0]?.max_seq || 0) + 1;
const paddedSeq = String(nextSeq).padStart(4, '0');
return `${prefix}${paddedSeq}`;
};

Examples:

  • January 2024: CL-202401-0001, CL-202401-0002, etc.
  • February 2024: CL-202402-0001, CL-202402-0002, etc.

Automated Features

  1. PSP Assignment: Automatic PSP selection based on country_code with fallback
  2. Admin User Creation: Secure password generation and user account setup
  3. Email Notification: Welcome email with login credentials sent automatically
  4. eKYC Initialization: Sets up PENDING eKYC status for compliance workflow
  5. Xendit Integration: Auto-create Xendit customers for Indonesia clients
  6. Email Logging: Track email delivery status in database

Database Transactions

All client creation operations use database transactions for data consistency:

try {
await db.query('BEGIN');

// 1. Email uniqueness validation
// 2. PSP selection and validation
// 3. Client code generation
// 4. Client record creation
// 5. Xendit business customer creation (Indonesia)
// 6. Admin user creation
// 7. Xendit individual customer creation (Indonesia admin)
// 8. Email logging
// 9. Email sending

await db.query('COMMIT');
} catch (error) {
await db.query('ROLLBACK');
throw error;
}

PSP Integration

PSP Selection Logic

// Primary PSP selection by country
const selectedPsp = await pspService.getPspByCountry(country_code);

// Fallback PSP query if primary fails
if (!selectedPsp?.psp_id) {
const fallbackPsp = await db.query(`
SELECT psp_id FROM psp_providers
WHERE country_code = $1 AND psp_type = 'FIAT_PSP'
ORDER BY priority ASC, created_at ASC
LIMIT 1
`, [country_code]);

psp_id = fallbackPsp.rows[0].psp_id;
}

PSP Types and Assignment

  • FIAT_PSP: Fiat currency payment service providers
  • Priority-based: Selection by configured priority levels
  • Country-specific: PSPs assigned per country code
  • Fallback System: Automatic fallback to available PSPs

Current PSP Providers:

  • Indonesia (ID): XENDIT (PSP ID: 11)
  • Singapore (SG): PSP_Singapore (PSP ID: 2)
  • United States (US): PSP_USA (PSP ID: 4)
  • India (IN): PSP_India (PSP ID: 3)
  • Australia (AU): PSP_Australia (PSP ID: 6)
  • Vietnam (VN): PSP_Vietnam (PSP ID: 10)

Xendit Integration

Auto-Creation for Indonesia Clients

When country_code = 'ID' and PSP is XENDIT, the system automatically creates:

  1. Business Customer (for the client organization)
  2. Individual Customer (for the admin user)
// Business customer creation
const clientPspData = {
client_id: newClient.client_id,
email: email,
client_alias: client_alias,
client_type: client_type,
phone: phone
};

const xenditCustomerResult = await pspService.getPspUser(clientPspData, country_code);

// Admin individual customer creation
const adminPspData = {
user_id: userResult.user_id,
email: email,
username: adminUser.username,
phone: phone
};

const adminXenditResult = await pspService.getPspUser(adminPspData, country_code);

Xendit Customer Types

  • BUSINESS: For client organizations

    • Links to client_id
    • Used for business operations and transactions
    • Higher transaction limits
  • INDIVIDUAL: For admin users

    • Links to user_id
    • Personal account for admin user
    • Standard individual limits

Xendit Error Handling

Xendit integration failures are non-blocking:

try {
xenditCustomerResult = await pspService.getPspUser(clientPspData, country_code);
} catch (xenditError) {
console.error('❌ [XENDIT] Error creating business customer:', xenditError.message);
// Don't fail the entire client creation, just log the error
console.warn(`⚠️ [XENDIT] Continuing client creation without Xendit integration`);
}

Email Service Integration

Admin Account Email Template

The system sends a welcome email with:

  • Admin username and email
  • Generated secure password
  • Frontend login URL
  • Account activation instructions
await sendEmail({
to: email,
subject: "Your AOL Core Admin Account",
htmlContent: sendEmailAdmin(adminUser.username, email, rawPassword, frontendUrl)
});

Secure Password Generation

const generateSecurePassword = () => {
const length = 10;
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@!#$%^&*()_+";
return Array.from(crypto.randomFillSync(new Uint8Array(length)))
.map(byte => charset[byte % charset.length])
.join('');
};

Email Logging

All email delivery is tracked in database:

INSERT INTO client_email_logs (client_id, email, subject, status, created_at)
VALUES ($1, $2, 'Your AOL Core Admin Account', 'SENT', CURRENT_TIMESTAMP)

Instance Management

Instance Lifecycle

  1. Creation: Admin creates instance with unique name within client
  2. Alias Management: Optional display name/alias updates for better identification
  3. Status Tracking: Active/inactive status management
  4. Deletion: Permanent removal from system (cannot be undone)

Access Control and Security

  • Client Ownership: Instances belong to specific clients
  • Admin Permissions: Only client admins can manage their instances
  • Database Validation: Ownership checks ensure proper access control
  • Transaction Safety: All operations use proper error handling

Instance Status Management

// Check user's client_id
const userResult = await db.query(`
SELECT client_id FROM users WHERE user_id = $1
`, [user_id]);

// Validate instance ownership before operations
const instanceResult = await db.query(`
SELECT * FROM instances WHERE instance_id = $1 AND client_id = $2
`, [instance_id, client_id]);

Database Schema

clients Table

CREATE TABLE clients (
client_id SERIAL PRIMARY KEY,
client_code VARCHAR(20) UNIQUE NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
client_alias VARCHAR(255) NOT NULL,
client_type VARCHAR(50) NOT NULL,
client_status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
ekyc_status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
country_code VARCHAR(3) NOT NULL,
psp_id INTEGER REFERENCES psp_providers(psp_id),
phone VARCHAR(20) NOT NULL,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

instances Table

CREATE TABLE instances (
instance_id SERIAL PRIMARY KEY,
client_id INTEGER NOT NULL REFERENCES clients(client_id) ON DELETE CASCADE,
instance_name VARCHAR(255) NOT NULL,
client_alias VARCHAR(255),
instance_status VARCHAR(20) DEFAULT 'ACTIVE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

client_email_logs Table

CREATE TABLE client_email_logs (
id SERIAL PRIMARY KEY,
client_id INTEGER NOT NULL REFERENCES clients(client_id) ON DELETE CASCADE,
email VARCHAR(255) NOT NULL,
subject VARCHAR(255) NOT NULL,
status VARCHAR(20) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

xendit_customers Table

CREATE TABLE xendit_customers (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(user_id) ON DELETE CASCADE,
client_id INTEGER REFERENCES clients(client_id) ON DELETE CASCADE,
xendit_customer_id VARCHAR(255) UNIQUE NOT NULL,
customer_type customer_type_enum NOT NULL,
status VARCHAR(50) DEFAULT 'ACTIVE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

xendit_accounts Table

CREATE TABLE xendit_accounts (
id SERIAL PRIMARY KEY,
xendit_customer_id VARCHAR(255) REFERENCES xendit_customers(xendit_customer_id),
account_type VARCHAR(50),
account_id VARCHAR(255),
currency VARCHAR(10) DEFAULT 'IDR',
balance NUMERIC(18,2) DEFAULT 0,
status VARCHAR(50) DEFAULT 'ACTIVE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

psp_providers Table Reference

CREATE TABLE psp_providers (
psp_id SERIAL PRIMARY KEY,
psp_name VARCHAR(50) NOT NULL,
country_code VARCHAR(3) NOT NULL,
api_endpoint VARCHAR(255),
currency_code VARCHAR(10),
psp_type VARCHAR(20),
priority INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Security Features

Password Security

  • Crypto-random Generation: 10-character passwords with mixed charset including special characters
  • bcrypt Hashing: Secure password storage with salt rounds
  • Email Delivery: Credentials sent via secure email service with logging

Access Control

  • Role-based Access: Admin-only endpoints protected by authMiddleware and roleMiddleware
  • Client Isolation: Users can only access their own client's instances
  • Database Validation: Ownership checks before all operations
  • JWT Authentication: Bearer token validation for all protected endpoints

Data Validation

  • Required Fields: Email, alias, type, country, phone validation
  • Email Uniqueness: Prevents duplicate client emails across system
  • PSP Availability: Ensures valid PSP for country before client creation
  • Transaction Safety: Database rollback on any failure

Xendit Security

  • PSP Service Integration: Secure Xendit customer creation via pspService
  • Country Validation: Xendit integration only for Indonesia (ID) clients
  • Error Handling: Xendit failures don't prevent client creation
  • Status Tracking: Customer status tracked in local database

Error Handling

Common Errors and Solutions

HTTPErrorCauseSolution
400Required fields missingMissing email, alias, type, country, or phoneProvide all mandatory fields
400No PSP availableCountry has no configured PSPConfigure PSP for country or use different country
400No FIAT PSP availableCountry has PSP but not FIAT typeConfigure FIAT_PSP for country
409Email already in useDuplicate email addressUse different email address
403Client ID not foundUser not linked to clientEnsure user has valid client association
403Access deniedInstance not owned by user's clientVerify instance ownership
404Client not foundInvalid client_id or user associationCheck user-client relationship
404Instance not foundInvalid instance_id or access deniedVerify instance exists and ownership
500Database transaction failedServer-side database issuesRetry request or contact support

Error Handling Pattern

try {
const result = await brdzSDK.client.createClientWithAdmin(clientData);
// Handle success
} catch (error) {
if (error.message.includes('Email, Name, Type, Country and Mobile Number are required')) {
// Handle validation error
showFieldValidationErrors();
} else if (error.message.includes('Email is already in use')) {
// Handle duplicate email
showEmailConflictError();
} else if (error.message.includes('No PSP available')) {
// Handle PSP configuration issue
showPspConfigurationError();
} else if (error.message.includes('Access denied')) {
// Handle authorization error
showAccessDeniedError();
} else {
// Handle generic error
showGenericError(error.message);
}
}

SDK Usage Examples

Complete Client Management Flow

const brdzSDK = require('@anantla/brdz-sdk');

class ClientManager {
constructor(sdk) {
this.sdk = sdk;
}

async createNewClient(clientData) {
try {
const client = await this.sdk.client;
const result = await client.createClientWithAdmin(clientData);

console.log('Client created:', result.client.client_code);
console.log('Admin user:', result.admin_user.username);

// Check Xendit integration for Indonesia
if (result.xendit_integration) {
console.log('Xendit Business Customer:', result.xendit_integration.business_customer?.customer_id);
console.log('Xendit Admin Customer:', result.xendit_integration.admin_customer?.customer_id);
}

return result;
} catch (error) {
throw new Error(`Client creation failed: ${error.message}`);
}
}

async getClientInstances() {
try {
const client = await this.sdk.client;
const instances = await client.getMyInstances();

console.log('Total instances:', instances.instances.length);
return instances;
} catch (error) {
throw new Error(`Failed to get instances: ${error.message}`);
}
}

async createNewInstance(instanceName) {
try {
const client = await this.sdk.client;
const result = await client.createInstance({ instance_name: instanceName });

console.log('Instance created:', result.instance.instance_name);
return result;
} catch (error) {
throw new Error(`Instance creation failed: ${error.message}`);
}
}

async updateInstanceAlias(instanceId, alias) {
try {
const client = await this.sdk.client;
const result = await client.updateInstanceAlias(instanceId, { alias });

console.log('Alias updated:', result.message);
return result;
} catch (error) {
throw new Error(`Alias update failed: ${error.message}`);
}
}

async deleteInstance(instanceId) {
try {
const client = await this.sdk.client;
const result = await client.deleteInstance(instanceId);

console.log('Instance deleted:', result.message);
return result;
} catch (error) {
throw new Error(`Instance deletion failed: ${error.message}`);
}
}
}

// Usage example
const clientManager = new ClientManager(brdzSDK);

// Create new client with admin
const newClientData = {
email: 'admin@techcorp.com',
client_alias: 'Tech Corporation',
client_type: 'CORPORATE',
country_code: 'ID',
phone: '+628123456789'
};

clientManager.createNewClient(newClientData)
.then(result => {
console.log('Client setup complete');
console.log('Client Code:', result.client.client_code);

if (result.xendit_integration) {
console.log('Xendit integration active for Indonesia client');
}
})
.catch(error => {
console.error('Client creation failed:', error.message);
});

// Manage instances
clientManager.getClientInstances()
.then(instances => {
console.log('Current instances:', instances.instances.length);

// Create new instance
return clientManager.createNewInstance('API Gateway');
})
.then(newInstance => {
console.log('New instance created:', newInstance.instance.instance_id);

// Update its alias
return clientManager.updateInstanceAlias(newInstance.instance.instance_id, 'Main API Gateway');
})
.then(updateResult => {
console.log('Instance alias updated');
})
.catch(error => {
console.error('Instance management failed:', error.message);
});

Client Creation

Client creation automatically handles PSP assignment, admin user setup, eKYC initialization, and Xendit integration for Indonesia clients.

Instance Deletion

Instance deletion is permanent and cannot be undone. Ensure proper confirmation before deletion.

Xendit Integration

Indonesia clients (country_code: 'ID') automatically get Xendit business and individual customer accounts created through PSP service integration.

Double Client Path

The delete instance endpoint uses /api/clients/clients/{instance_id} due to the base route structure where /clients is the base path and /clients/:instance_id is the specific endpoint.