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
  • feeHash must be valid and not expired
  • feeHash can 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 purpose must 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 success
  • data: Complete payroll request object
    • id: Unique identifier for this payroll request
    • sourceAccountCurrencyId: Source account currency UUID
    • sourceAccountCurrency: Detailed source account information including balance and currency details
    • payrollAccountCurrencyId: Payroll account currency UUID
    • payrollAccountCurrency: Detailed payroll account information
    • totalAmount: Total debited from source account (includes all fees)
    • status: Current request status (initially PENDING)
    • estimatedFxRate: Estimated exchange rate (actual rate provided later in quote)
    • estimatedReceivedAmount: Total amount beneficiaries expected to receive
    • sourceAmountForExchange: Amount available for FX conversion (total - spread fee - fuse fee)
    • metadata: Contains detailed fee breakdown
    • amountSplitDetails: Array of per-beneficiary payment instructions with snapshots
    • transfers: Array of related transfers (source debit + beneficiary payout placeholders)
    • customer: Customer details
    • createdAt: Request creation timestamp
    • updatedAt: 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_BENEFICIARY transfer placeholders (status: PENDING)
  • One placeholder per beneficiary for tracking
  • Links each placeholder to corresponding amount split

6. Source Transfer Initiation

  • Creates FUSE_INTERNAL_DEBIT transfer for total amount
  • Submits payment to XBD internal Fuse account
  • Updates transfer status to PROCESSING with 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:

  • PENDING
  • QUOTE_PROVIDED
  • QUOTE_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

Copyright © 2025 Relm