Direct Disbursements API

This page documents the live public direct-disbursement surface served under https://api.gopiaxis.com/api.

Overview

Public direct-disbursement routes:

  • POST /api/disbursements/quote

  • POST /api/disbursements

  • GET /api/disbursements

  • GET /api/disbursements/{disbursement_id}

  • POST /api/disbursements/{disbursement_id}/cancel

Public Contract Notes

The guaranteed create-disbursement request schema is:

  • recipients

  • currency

  • payment_method

  • description

Each recipient guarantees:

  • recipient_id

  • email

  • phone_number

  • amount

  • reference

If you see longer examples elsewhere with keys such as callback_url, notify_recipients, metadata, or bulk-upload helpers, treat those as deployment-specific extensions and not part of the guaranteed public contract.

How recipient resolution works

Each recipient item follows one of two paths:

  • recipient_id present: internal Piaxis transfer to that Piaxis account

  • recipient_id omitted: external payout through the batch payment_method

When present, recipient_id must be a Piaxis Account.id. Do not send a MerchantProfile.id or UserProfile.id there.

For external mobile-money payouts:

  • phone_number is the routing field that matters for MTN and Airtel

  • email is optional metadata, not the mobile-money routing key

  • the beneficiary does not need to be a Piaxis user

When recipient_id is needed

Use recipient_id only when the beneficiary should receive funds into a Piaxis wallet.

Typical cases:

  • a merchant wants to pay another business that already uses Piaxis

  • a platform wants to pay a service provider into that provider’s Piaxis wallet

  • you have already connected the beneficiary through the public OAuth flow and persisted the returned user_id

How to obtain a Piaxis recipient_id safely:

  1. send the beneficiary through GET /api/authorize

  2. exchange the authorization code through POST /api/token

  3. persist the returned user_id from the token response

  4. later use that stored user_id as recipients[].recipient_id

If the beneficiary should receive on external mobile money instead, do not use recipient_id. Omit it and send the payout phone number with the batch payment_method.

Payment-method scope

payment_method is a top-level batch field.

That means:

  • all external recipients in one batch use the same payout rail

  • if you need some recipients paid by MTN and others by Airtel, create separate batches

  • internal recipients identified by recipient_id are processed as internal wallet transfers and do not depend on the external payout rail

For the currently documented public mobile-money payout rail, use mtn or airtel.

Authentication

Use merchant API key authentication:

 api-key: YOUR_MERCHANT_API_KEY
 Content-Type: application/json
X-piaxis-Client-ID: YOUR_MERCHANT_CLIENT_ID

Create Disbursement

Quote Disbursement

POST /api/disbursements/quote

Preview recipient-level fees and the total merchant wallet debit before submitting a payout batch.

Guaranteed quote response fields

  • currency

  • payment_method

  • recipient_count

  • internal_recipient_count

  • external_recipient_count

  • total_amount

  • internal_total_amount

  • external_total_amount

  • total_fee_amount

  • total_debit_amount

  • items

Representative response shape

{
  "currency": "UGX",
  "payment_method": "mtn",
  "recipient_count": 2,
  "internal_recipient_count": 0,
  "external_recipient_count": 2,
  "total_amount": "2750000.00",
  "internal_total_amount": "0.00",
  "external_total_amount": "2750000.00",
  "total_fee_amount": "2500.00",
  "total_debit_amount": "2752500.00",
  "items": [
    {
      "recipient_id": null,
      "email": null,
      "phone_number": "+256700123456",
      "amount": "1500000.00",
      "payout_type": "external",
      "fee_amount": "1500.00",
      "total_debit_amount": "1501500.00",
      "reference": "SALARY-JUNE-001",
      "fee_breakdown": [
        {
          "fee_id": "00000000-0000-0000-0000-000000000001",
          "fee_name": "Default disbursement fee",
          "fee_type": "tiered",
          "amount": "1500.00",
          "description": "Default UGX disbursement fee tier"
        }
      ]
    }
  ]
}
POST /api/disbursements

Create a direct disbursement batch.

Canonical example

 POST /api/disbursements HTTP/1.1
 Host: api.gopiaxis.com
 api-key: YOUR_API_KEY
 Content-Type: application/json
X-piaxis-Client-ID: YOUR_MERCHANT_CLIENT_ID

 {
   "recipients": [
     {
       "recipient_id": "096b723a-45c5-4957-94d7-747835136265",
       "email": "[email protected]",
       "phone_number": "+256700123456",
       "amount": "1500000.00",
       "reference": "SALARY-JUNE-001"
     },
     {
       "email": "[email protected]",
       "phone_number": "+256700654321",
       "amount": "1250000.00",
       "reference": "SALARY-JUNE-002"
     }
   ],
   "currency": "UGX",
   "payment_method": "mtn",
   "description": "June contractor payouts"
 }

External mobile-money rules

For an external mobile-money recipient in this route:

  • include phone_number

  • choose the batch payment_method as mtn or airtel

  • do not assume recipient_id is required

  • do not assume the beneficiary needs a Piaxis account

If you only send email and omit both recipient_id and phone_number, the request may pass schema validation but it is not a valid MTN or Airtel payout target.

Guaranteed create response

{
  "disbursement_id": "b6b93a8b-2c81-44bf-9d98-9a43f725b90f",
  "status": "processing",
  "total_amount": "2750000.00",
  "total_fee_amount": "2500.00",
  "total_debit_amount": "2752500.00",
  "internal_total_amount": "0.00",
  "external_total_amount": "2750000.00",
  "currency": "UGX",
  "recipient_count": 2,
  "successful_count": 0,
  "failed_count": 0,
  "pending_count": 2
}

Get Disbursement

GET /api/disbursements/{disbursement_id}

Guaranteed response fields:

  • disbursement_id

  • status

  • total_amount

  • total_fee_amount

  • total_debit_amount

  • internal_total_amount

  • external_total_amount

  • currency

  • payment_method

  • description

  • created_at

  • completed_at

  • cancelled_at

  • cancellation_reason

  • items

List Disbursements

GET /api/disbursements

Supported query parameters:

  • status

  • from_date

  • to_date

  • offset

  • limit

Representative response shape

{
  "total": 1,
  "offset": 0,
  "limit": 50,
  "results": [
    {
      "disbursement_id": "b6b93a8b-2c81-44bf-9d98-9a43f725b90f",
      "status": "processing",
      "total_amount": "2750000.00",
      "total_fee_amount": "2500.00",
      "total_debit_amount": "2752500.00",
      "internal_total_amount": "0.00",
      "external_total_amount": "2750000.00",
      "currency": "UGX",
      "recipient_count": 2,
      "successful_count": 0,
      "failed_count": 0,
      "pending_count": 2
    }
  ]
}

Cancel Disbursement

POST /api/disbursements/{disbursement_id}/cancel

Guaranteed request field:

  • reason

Example

{
  "reason": "Incorrect recipient information"
}

Marketplace Mapping

For platform payouts, keep two beneficiary concepts clearly separated:

  • internal Piaxis beneficiary: map your beneficiary id to a trusted Piaxis recipient_id

  • external mobile-money beneficiary: store the beneficiary phone number and intended payout method in your own beneficiary directory

For the internal-wallet path, that mapped recipient_id is always the beneficiary’s Piaxis Account.id.

Never let raw recipient ids come directly from end-user form input.

Marketplace collect -> release -> payout example

For a platform or merchant-funded marketplace:

  1. collect from the customer with direct payment or escrow

  2. the merchant or platform wallet receives the collected funds

  3. if you used escrow, release the escrow to the merchant or platform account named in receiver_id

  4. call POST /api/disbursements/quote

  5. create a disbursement batch to the final beneficiary phone number

Example external payout item:

Collect to merchant:

{
  "amount": "50000.00",
  "currency": "UGX",
  "payment_method": "mtn",
  "user_info": {
    "email": "[email protected]",
    "phone_number": "+256700000000"
  }
}

Release or settle to the merchant/platform wallet, then disburse:

{
  "recipients": [
    {
      "phone_number": "+256700123456",
      "amount": "45000.00",
      "reference": "ORDER-1001-NET-PAYOUT"
    }
  ],
  "currency": "UGX",
  "payment_method": "airtel",
  "description": "Net payout after platform fee"
}

This flow does not require the final beneficiary to have a Piaxis account.

Fee Behaviour

Disbursement fees are configurable through the Piaxis fee policy system and can be targeted by merchant, company, role, account type, and channel. When no merchant-specific rule is configured, the public UGX direct-disbursement surface uses this default tier for external mobile-money style payouts:

  • up to 100000 UGX: 500 UGX

  • above 100000 UGX up to 1000000 UGX: 1000 UGX

  • above 1000000 UGX: 1500 UGX

Internal recipient transfers do not apply this external payout fee tier.