Create Payroll Request
This endpoint initiates a payroll distribution to multiple beneficiaries. It requires a valid feeHash obtained from the Estimate Payroll Fee endpoint. Upon creation, funds are immediately debited from the source account and the request enters PENDING status awaiting admin quote.
Request
Method: POST
URL: /v1/customers/payroll/requests
Authentication: Requires Bearer token
Content-Type: application/json
Request Body
{
"sourceAccountCurrencyId": "385dec3a-9bfe-4072-8733-7872ef350e71",
"payrollAccountCurrencyId": "fae535c5-f64f-4737-82de-c12b88be0764",
"feeHash": "a7c8f3d2-4b9e-4d1a-8f2c-9e7d6c5b4a3f",
"amountSplitDetails": [
{
"beneficiaryId": "5b9d9177-2261-458d-b65b-c6722cc75a90",
"amount": "5000.00",
"purpose": "FCISS",
"amountCurrencyType": "SOURCE"
},
{
"beneficiaryId": "0db9b611-9754-454d-951d-d691e1265148",
"amount": "150000.00",
"purpose": "PEN",
"amountCurrencyType": "PAYROLL"
}
]
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
sourceAccountCurrencyId | UUID | ✅ | The account currency ID from which funds will be debited |
payrollAccountCurrencyId | UUID | ✅ | The payroll account currency ID |
feeHash | UUID | ✅ | The fee hash obtained from the estimate endpoint |
amountSplitDetails | Array | ✅ | List of beneficiary payment details |
amountSplitDetails[].beneficiaryId | UUID | ✅ | The unique identifier of the beneficiary |
amountSplitDetails[].amount | String (Decimal) | ✅ | Payment amount |
amountSplitDetails[].purpose | String | ✅ | MCB purpose code (see below) |
amountSplitDetails[].amountCurrencyType | Enum | ❌ | Currency type: SOURCE or PAYROLL (defaults to SOURCE) |
Validation Rules
- All fields are required except
amountCurrencyType feeHashmust be valid and not expiredfeeHashcan only be used once (consumed upon request creation)- Source and payroll account currency IDs must match the estimate
- Amount split details must match the estimate
- Each
purposemust be a valid MCB purpose code - Customer must own the source account currency
- Source account must have sufficient available balance
Example Request
curl --location 'https://sandbox.api.relm.co/v1/customers/payroll/requests' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <your_access_token>' \
--data '{
"sourceAccountCurrencyId": "385dec3a-9bfe-4072-8733-7872ef350e71",
"payrollAccountCurrencyId": "fae535c5-f64f-4737-82de-c12b88be0764",
"feeHash": "a7c8f3d2-4b9e-4d1a-8f2c-9e7d6c5b4a3f",
"amountSplitDetails": [
{
"beneficiaryId": "5b9d9177-2261-458d-b65b-c6722cc75a90",
"amount": "5000.00",
"purpose": "FCISS",
"amountCurrencyType": "SOURCE"
},
{
"beneficiaryId": "0db9b611-9754-454d-951d-d691e1265148",
"amount": "150000.00",
"purpose": "PEN",
"amountCurrencyType": "PAYROLL"
}
]
}'
Response
Status Code: 201 Created
Content-Type: application/json
Response Body
Response Description: On successful creation, the server responds with a status code of 201 and a JSON object containing the complete payroll request details.
{
"success": true,
"data": {
"id": "babe5f2d-7c44-4b83-90b9-f94856ed4643",
"sourceAccountCurrencyId": "385dec3a-9bfe-4072-8733-7872ef350e71",
"sourceAccountCurrency": {
"id": "385dec3a-9bfe-4072-8733-7872ef350e71",
"accountId": "fae535c5-f64f-4737-82de-c12b88be0764",
"currency": {
"id": "0ff5db18-ad57-4703-a031-08907aa814f1",
"currencyCode": "AED",
"currencyName": "United Arab Emirates Dirham",
"currencySymbol": "د.إ"
},
"balance": "50000.00",
"available": "44154.68",
"account": {
"id": "fae535c5-f64f-4737-82de-c12b88be0764",
"accountProvider": "FUSE",
"customerId": "c9a8b7d6-5e4f-3d2c-1b0a-9f8e7d6c5b4a"
}
},
"payrollAccountCurrencyId": "fae535c5-f64f-4737-82de-c12b88be0764",
"payrollAccountCurrency": {
"id": "fae535c5-f64f-4737-82de-c12b88be0764",
"currency": {
"currencyCode": "PKR",
"currencyName": "Pakistani Rupee"
},
"account": {
"accountProvider": "MCB"
}
},
"totalAmount": "5845.32",
"status": "PENDING",
"estimatedFxRate": "91.2450",
"estimatedReceivedAmount": "457892.50",
"sourceAmountForExchange": "5730.12",
"metadata": {
"feeBreakdown": {
"sourceCurrencyAmount": "5000.00",
"spreadFee": "75.00",
"fuseFee": "40.20",
"mcbFee": "730.12",
"totalFee": "845.32",
"estimatedReceivedAmount": "457892.50",
"payrollCurrencyCode": "PKR",
"feeCurrencyCode": "AED",
"exchangeRate": "91.2450",
"baseRate": "92.6210"
}
},
"amountSplitDetails": [
{
"id": "d3c2b1a0-9f8e-7d6c-5b4a-3f2e1d0c9b8a",
"beneficiaryId": "5b9d9177-2261-458d-b65b-c6722cc75a90",
"beneficiarySnapshot": {
"id": "5b9d9177-2261-458d-b65b-c6722cc75a90",
"firstName": "Ahmed",
"lastName": "Khan",
"displayName": "Ahmed Khan",
"type": "INDIVIDUAL",
"iban": "PK36MUCB0000001234567890",
"bankName": "MCB Bank",
"nationality": "PK",
"reference": "Freelancer Payment"
},
"sourceCurrencyAmount": "5000.00",
"amount": "456062.50",
"purposeCode": "FCISS",
"payoutTransferId": "e4d3c2b1-0a9f-8e7d-6c5b-4a3f2e1d0c9b",
"createdAt": "2026-06-05T09:15:30.123Z"
},
{
"id": "f5e4d3c2-b1a0-9f8e-7d6c-5b4a3f2e1d0c",
"beneficiaryId": "0db9b611-9754-454d-951d-d691e1265148",
"beneficiarySnapshot": {
"id": "0db9b611-9754-454d-951d-d691e1265148",
"firstName": "Fatima",
"lastName": "Ali",
"displayName": "Fatima Ali",
"type": "INDIVIDUAL",
"accountNumber": "0987654321",
"bankName": "MCB Bank",
"nationality": "PK"
},
"sourceCurrencyAmount": "1644.12",
"amount": "150000.00",
"purposeCode": "PEN",
"payoutTransferId": "g6f5e4d3-c2b1-a0a9-f8e7-d6c5b4a3f2e1",
"createdAt": "2026-06-05T09:15:30.123Z"
}
],
"transfers": [
{
"id": "h7g6f5e4-d3c2-b1a0-9f8e-7d6c5b4a3f2e",
"payrollRequestId": "babe5f2d-7c44-4b83-90b9-f94856ed4643",
"transferType": "FUSE_INTERNAL_DEBIT",
"status": "PROCESSING",
"externalId": "fuse_tx_123456789",
"amount": "5845.32",
"currencyCode": "AED",
"createdAt": "2026-06-05T09:15:30.456Z"
},
{
"id": "e4d3c2b1-0a9f-8e7d-6c5b-4a3f2e1d0c9b",
"payrollRequestId": "babe5f2d-7c44-4b83-90b9-f94856ed4643",
"transferType": "MCB_TO_BENEFICIARY",
"status": "PENDING",
"amount": "456062.50",
"currencyCode": "PKR",
"createdAt": "2026-06-05T09:15:30.567Z"
},
{
"id": "g6f5e4d3-c2b1-a0a9-f8e7-d6c5b4a3f2e1",
"payrollRequestId": "babe5f2d-7c44-4b83-90b9-f94856ed4643",
"transferType": "MCB_TO_BENEFICIARY",
"status": "PENDING",
"amount": "150000.00",
"currencyCode": "PKR",
"createdAt": "2026-06-05T09:15:30.678Z"
}
],
"customer": {
"id": "c9a8b7d6-5e4f-3d2c-1b0a-9f8e7d6c5b4a",
"firstName": "Business",
"lastName": "Owner",
"company": {
"legalName": "Tech Innovations Ltd"
}
},
"createdAt": "2026-06-05T09:15:30.123Z",
"updatedAt": "2026-06-05T09:15:30.789Z"
}
}
Response Fields
success: Boolean indicating request successdata: Complete payroll request objectid: Unique identifier for this payroll requestsourceAccountCurrencyId: Source account currency UUIDsourceAccountCurrency: Detailed source account information including balance and currency detailspayrollAccountCurrencyId: Payroll account currency UUIDpayrollAccountCurrency: Detailed payroll account informationtotalAmount: Total debited from source account (includes all fees)status: Current request status (initiallyPENDING)estimatedFxRate: Estimated exchange rate (actual rate provided later in quote)estimatedReceivedAmount: Total amount beneficiaries expected to receivesourceAmountForExchange: Amount available for FX conversion (total - spread fee - fuse fee)metadata: Contains detailed fee breakdownamountSplitDetails: Array of per-beneficiary payment instructions with snapshotstransfers: Array of related transfers (source debit + beneficiary payout placeholders)customer: Customer detailscreatedAt: Request creation timestampupdatedAt: Last update timestamp
Business Logic Flow
The request creation process executes the following steps:
1. Fee Hash Validation
- Retrieves fee hash data from Redis cache
- Validates hash has not expired
- Confirms account currency IDs match the estimate
- Deletes the hash to prevent reuse (one-time consumption)
2. Precondition Checks
- Verifies customer owns the source account currency
- Validates source account has sufficient available balance
- Confirms all beneficiaries exist and match the estimate
- Validates all purpose codes are valid MCB codes
3. PayrollRequest Creation
- Creates main PayrollRequest record with status
PENDING - Stores complete fee breakdown in metadata field
- Records estimated exchange rate and expected amounts
4. Amount Split Creation
- Creates PayrollAmountSplit record for each beneficiary
- Captures immutable beneficiary snapshot (name, account details, etc.)
- Stores both source and payroll currency amounts
- Links to MCB purpose code for compliance
5. Transfer Placeholder Creation
- Creates
MCB_TO_BENEFICIARYtransfer placeholders (status:PENDING) - One placeholder per beneficiary for tracking
- Links each placeholder to corresponding amount split
6. Source Transfer Initiation
- Creates
FUSE_INTERNAL_DEBITtransfer for total amount - Submits payment to XBD internal Fuse account
- Updates transfer status to
PROCESSINGwith external transaction ID - Records pending transaction against source account currency
Status Workflow
graph LR
A[PENDING] --> B[QUOTE_PROVIDED]
B --> C{Customer Action}
C -->|Accept| D[QUOTE_ACCEPTED]
C -->|Cancel| E[CANCELLED]
D --> F[EXECUTING]
F --> G[PAYOUT_INITIATED]
G --> H{Payout Results}
H -->|All Success| I[COMPLETED]
H -->|Some Success| J[PARTIALLY_COMPLETED]
H -->|All Failed| K[FAILED]
A -->|Cancel| E
B -->|Cancel| E
D -->|Cancel| E
Cancellable Statuses
Requests can be cancelled by the customer or admin when in the following statuses:
PENDINGQUOTE_PROVIDEDQUOTE_ACCEPTED
Once execution begins (EXECUTING or later), cancellation is no longer possible.
MCB Purpose Codes
The purpose field must be one of the following valid MCB codes:
| Purpose Code | Numeric Code | Description |
|---|---|---|
FCISS | 9186 | Freelance of Computer and Information Systems Services |
PEN | 9477 | Pension Transactions |
OFS | 9249 | Other Freelance Services |
For complete purpose code reference, see Enums & Types.
Beneficiary Snapshots
Each amountSplitDetails entry includes a beneficiarySnapshot field containing an immutable copy of the beneficiary’s details at the time of request creation:
{
"beneficiarySnapshot": {
"id": "uuid",
"firstName": "string",
"lastName": "string",
"displayName": "string",
"type": "INDIVIDUAL|BUSINESS",
"iban": "string",
"accountNumber": "string",
"routingNumber": "string",
"bankName": "string",
"nationality": "string",
"reference": "string"
}
}
Purpose: Ensures historical accuracy even if beneficiary details are updated later. Critical for audit, compliance, and dispute resolution.
Error Cases
400 Bad Request
Invalid or expired fee hash:
{
"success": false,
"error": {
"code": "INVALID_FEE_HASH",
"message": "Fee hash is invalid or has expired"
}
}
Insufficient balance:
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Source account has insufficient available balance"
}
}
Invalid purpose code:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid MCB purpose code. Must be one of: FCISS, PEN, OFS"
}
}
401 Unauthorized
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired authentication token"
}
}
403 Forbidden
Customer doesn’t own source account:
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "Source account currency does not belong to authenticated customer"
}
}
404 Not Found
Beneficiary not found:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "One or more beneficiaries not found"
}
}
Important Notes
- Fee Hash: Consumed immediately upon request creation (cannot be reused)
- Source Funds: Debited immediately and held for the payroll
- Quote Workflow: After creation, wait for admin to provide FX quote (status changes to
QUOTE_PROVIDED) - Beneficiary Snapshots: Stored permanently for compliance and audit purposes
- Transfer Tracking: Monitor individual beneficiary payouts via the List Payroll Transfers endpoint
- Balance Impact: Source account’s available balance is reduced immediately, even though beneficiaries haven’t been paid yet