> ## Documentation Index
> Fetch the complete documentation index at: https://docs.afriex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Models

> Data models, enumerations, and field references for the Afriex Business API

This page documents the key data models returned and accepted by the API, including all enumerated values and field-level details.

***

## Customer

| Field         | Type              | Description                                                                                 |
| ------------- | ----------------- | ------------------------------------------------------------------------------------------- |
| `customerId`  | string            | Unique identifier for the customer                                                          |
| `name`        | string            | Full name of the customer                                                                   |
| `email`       | string (email)    | Email address                                                                               |
| `phone`       | string            | Phone number in [E.164 format](https://en.wikipedia.org/wiki/E.164) (e.g. `+2348192837465`) |
| `countryCode` | string            | ISO 3166-1 alpha-2 country code (e.g. `NG`)                                                 |
| `meta`        | object            | Optional metadata you attach to the customer                                                |
| `createdAt`   | string (ISO 8601) | Timestamp when the customer was created                                                     |
| `updatedAt`   | string (ISO 8601) | Timestamp of the last update                                                                |

<Note>
  On create and update requests, supply the customer's full name as `fullName`; responses return it as `name`. KYC details are submitted separately through the [Update KYC](/api-reference/endpoint/customers/update-kyc) endpoint.
</Note>

***

## Transaction

| Field                 | Type              | Description                                                                            |
| --------------------- | ----------------- | -------------------------------------------------------------------------------------- |
| `transactionId`       | string            | Unique identifier for the transaction                                                  |
| `customerId`          | string            | ID of the customer who owns this transaction                                           |
| `sourceId`            | string            | ID of the source payment method                                                        |
| `destinationId`       | string            | ID of the destination payment method                                                   |
| `sourceAmount`        | string            | Amount debited from the source wallet                                                  |
| `sourceCurrency`      | string            | ISO 4217 currency code of the source wallet (e.g. `USD`)                               |
| `destinationAmount`   | string            | Amount credited to the destination                                                     |
| `destinationCurrency` | string            | ISO 4217 currency code of the destination (e.g. `NGN`)                                 |
| `type`                | string            | Transaction type. See [Transaction Types](#transaction-types)                          |
| `channel`             | string            | Payment channel of the transaction. See [Transaction Channels](#transaction-channels). |
| `status`              | string            | Current status. See [Transaction Statuses](#transaction-statuses)                      |
| `merchantReference`   | string            | Merchant-supplied reference (mirrors `meta.reference` from the create request)         |
| `meta`                | object            | Metadata attached to the transaction. See [TransactionMeta](#transactionmeta)          |
| `createdAt`           | string (ISO 8601) | Timestamp when the transaction was created                                             |
| `updatedAt`           | string (ISO 8601) | Timestamp of the last update                                                           |

### Transaction Types

| Value      | Description                                                       |
| ---------- | ----------------------------------------------------------------- |
| `WITHDRAW` | Send funds from the Afriex wallet to a recipient's payment method |
| `DEPOSIT`  | Receive funds into the Afriex wallet                              |
| `SWAP`     | Convert funds between currencies within the Afriex wallet         |

### Transaction Channels

| Channel                | Description                                 |
| ---------------------- | ------------------------------------------- |
| `BANK_ACCOUNT`         | Local bank account transfer                 |
| `SWIFT`                | International SWIFT wire transfer           |
| `MOBILE_MONEY`         | Mobile money wallet (e.g. M-Pesa, MTN MoMo) |
| `UPI`                  | Unified Payments Interface (India)          |
| `INTERAC`              | Interac e-Transfer (Canada)                 |
| `WE_CHAT`              | WeChat Pay                                  |
| `CARD`                 | Card payment                                |
| `CRYPTO`               | Crypto rail                                 |
| `VIRTUAL_BANK_ACCOUNT` | Hosted virtual bank account                 |
| `POOL_ACCOUNT`         | Shared pool account for incoming deposits   |
| `ACH_BANK_ACCOUNT`     | US ACH bank transfer                        |
| `PAYBILL_TILL`         | Paybill / Till (M-Pesa business numbers)    |
| `RFP`                  | Request for Payment                         |
| `VIRTUAL_CARD`         | Virtual card                                |
| `ALIPAY`               | Alipay                                      |
| `WALLET`               | Afriex wallet (internal leg)                |

### Transaction Statuses

| Status                       | Description                                                                                                  |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `PENDING`                    | Transaction has been received and is awaiting processing                                                     |
| `PROCESSING`                 | Transaction is actively being processed                                                                      |
| `SUCCESS`                    | Transaction settled successfully                                                                             |
| `FAILED`                     | Transaction failed. Check `meta.failureReason` for the reason code. See [Failure reasons](#failure-reasons). |
| `CANCELLED`                  | Transaction was cancelled before processing                                                                  |
| `REFUNDED`                   | Funds were returned to the sender                                                                            |
| `RETRY`                      | Transaction is being automatically retried                                                                   |
| `UNKNOWN`                    | Status could not be determined. Contact support.                                                             |
| `SCHEDULED`                  | Transaction is scheduled to be processed later                                                               |
| `CUSTOMER_ACTION_REQUIRED`   | Transaction is paused pending an action from the customer                                                    |
| `REJECTED`                   | Transaction was rejected after review                                                                        |
| `IN_REVIEW`                  | Transaction is under manual review                                                                           |
| `DISPUTED`                   | A dispute has been raised against the transaction                                                            |
| `DISPUTE_RESOLVED`           | The dispute has been resolved                                                                                |
| `DISPUTE_WON`                | The dispute was resolved in your favour                                                                      |
| `DISPUTE_LOST`               | The dispute was resolved against you                                                                         |
| `DISPUTE_EVIDENCE_SUBMITTED` | Evidence has been submitted for the dispute                                                                  |

<Tip>
  Subscribe to [Transaction Events](/api-reference/endpoint/webhooks/transaction-events) to receive real-time status updates instead of polling the API.
</Tip>

***

## TransactionMeta

The `meta` object passed when creating a transaction. `idempotencyKey` and `reference` are required.

| Field            | Type   | Required | Description                                                                                                      |
| ---------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------- |
| `idempotencyKey` | string | **Yes**  | Unique key to prevent duplicate transactions. Use a UUID or your own unique identifier.                          |
| `reference`      | string | **Yes**  | Your internal reference for the transaction (e.g. order ID). Returned on the transaction as `merchantReference`. |
| `narration`      | string | No       | Human-readable reason or description for the transaction                                                         |
| `invoice`        | string | No       | Base64-encoded invoice document to attach to the transaction                                                     |

```json theme={null}
{
  "meta": {
    "idempotencyKey": "550e8400-e29b-41d4-a716-446655440000",
    "reference": "ORDER-12345",
    "narration": "Payment for invoice #12345",
    "invoice": "base64EncodedStringHere"
  }
}
```

<Warning>
  Always provide a unique `idempotencyKey` per transaction attempt. If you retry a failed request with the same key, Afriex will return the original transaction instead of creating a duplicate.
</Warning>

### Server-set meta fields

Afriex also sets fields on `meta` after the transaction is created. These echo alongside any fields you passed on create.

| Field           | Type    | Description                                                                                                                                                                       |
| --------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `otpRequired`   | boolean | `true` when the customer must complete an OTP challenge before the transaction can settle. See [Simulating OTP-required deposits](/development#simulating-otp-required-deposits). |
| `failureReason` | object  | Present only when `status` is `FAILED` or `REJECTED`. Carries a stable `code`, a customer-safe `message`, and a `retryable` flag. See [Failure reasons](#failure-reasons).        |

### Failure reasons

When a transaction reaches `FAILED` or `REJECTED`, `meta.failureReason` explains why using a stable `AFX_*` code and a customer-safe message. Branch on `code` rather than the underlying rail so your integration stays stable across routing changes.

| Field       | Type    | Description                                                                                                                                                                          |
| ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `code`      | string  | Stable `AFX_*` failure code. Safe to switch on; the set grows over time but existing values do not change meaning.                                                                   |
| `message`   | string  | Customer-safe short description of the failure. Suitable for display; do not parse. Branch on `code` instead.                                                                        |
| `retryable` | boolean | `true` when re-submitting the same request (or, for `AFX_PROPOSAL_EXPIRED`, starting a fresh proposal) may succeed. `false` when the caller must change the request before retrying. |

```json theme={null}
{
  "meta": {
    "failureReason": {
      "code": "AFX_VELOCITY_LIMIT_EXCEEDED",
      "message": "This transaction exceeds the allowed velocity limit. Try again later.",
      "retryable": true
    }
  }
}
```

| Code                          | Meaning                                                                                 |
| ----------------------------- | --------------------------------------------------------------------------------------- |
| `AFX_REQUEST_FAILED`          | Generic failure while processing the request. Usually retryable.                        |
| `AFX_SYSTEM_ERROR`            | Internal Afriex error. Retry with backoff.                                              |
| `AFX_SERVICE_UNAVAILABLE`     | A downstream service was unavailable. Retry with backoff.                               |
| `AFX_INVALID_CURRENCY`        | The requested currency is not supported for this route.                                 |
| `AFX_INVALID_AMOUNT`          | The requested amount is invalid or outside allowed limits.                              |
| `AFX_INVALID_RECIPIENT`       | The recipient payment method is invalid or incomplete.                                  |
| `AFX_RECIPIENT_NOT_FOUND`     | The recipient account could not be located at the destination institution.              |
| `AFX_BENEFICIARY_RESTRICTED`  | The beneficiary is restricted and cannot receive funds.                                 |
| `AFX_INVALID_SENDER`          | The sender's payment method is invalid or ineligible.                                   |
| `AFX_INVALID_REQUEST`         | The request payload is malformed or inconsistent.                                       |
| `AFX_VELOCITY_LIMIT_EXCEEDED` | The customer has exceeded a velocity limit. Retry after the window resets.              |
| `AFX_AMOUNT_LIMIT_EXCEEDED`   | The request exceeds a per-transaction, daily, or account limit.                         |
| `AFX_PAYMENT_FAILED`          | The payment leg failed at the payment rail.                                             |
| `AFX_COMPLIANCE_REJECTED`     | The transaction was rejected during compliance review.                                  |
| `AFX_PROPOSAL_EXPIRED`        | The rate proposal expired before the transaction was committed. Start a fresh proposal. |

<Note>
  The `AFX_*` set may grow over time as new failure modes are surfaced. Existing values will not change meaning. Handle unknown codes by falling back to `message`.
</Note>

***

## PaymentMethod

Empty fields are omitted from responses. Account-shaped channels (`BANK_ACCOUNT`, `MOBILE_MONEY`, `SWIFT`, etc.) populate `accountName`, `accountNumber`, and `institution`; the `CARD` channel instead populates `last4`, `brand`, `expiration`, and `cardName`.

| Field              | Type      | Description                                                                                                                                                                                   |
| ------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `paymentMethodId`  | string    | Unique identifier for the payment method                                                                                                                                                      |
| `customerId`       | string    | ID of the customer who owns this payment method                                                                                                                                               |
| `channel`          | string    | Payment channel. See [Payment Channels](#payment-channels)                                                                                                                                    |
| `countryCode`      | string    | ISO 3166-1 alpha-2 country code                                                                                                                                                               |
| `currency`         | string    | ISO 4217 currency code. Use this instead of inferring from `countryCode`, which is ambiguous (e.g. a USD account in a non-US country)                                                         |
| `capabilities`     | string\[] | Operations this method is enabled for (e.g. `DEPOSIT`, `WITHDRAW`). Filterable via the `capabilities` query parameter on [List Payment Methods](/api-reference/endpoint/payment-methods/list) |
| `reference`        | string    | Identifier used to reconcile incoming deposits against                                                                                                                                        |
| `accountName`      | string    | Account holder name. Present for account-shaped channels                                                                                                                                      |
| `accountNumber`    | string    | Account number. Present for account-shaped channels                                                                                                                                           |
| `institution`      | object    | Bank or provider details. See [PaymentMethodInstitution](#paymentmethodinstitution)                                                                                                           |
| `recipient`        | object    | Recipient contact details. See [PaymentMethodRecipient](#paymentmethodrecipient)                                                                                                              |
| `transaction`      | object    | Per-transaction overrides. See [PaymentMethodTransaction](#paymentmethodtransaction)                                                                                                          |
| `status`           | string    | Lifecycle status. See [Payment Method Statuses](#payment-method-statuses)                                                                                                                     |
| `last4`            | string    | Last 4 digits of the card. `CARD` channel only                                                                                                                                                |
| `brand`            | string    | Card brand (e.g. `Visa`, `MasterCard`). `CARD` channel only                                                                                                                                   |
| `expiration`       | object    | Card expiry with `month` and `year`. `CARD` channel only                                                                                                                                      |
| `cardName`         | string    | Name on the card. `CARD` channel only                                                                                                                                                         |
| `expiresInMinutes` | integer   | Minutes until a dynamic virtual account expires, when applicable                                                                                                                              |
| `amount`           | number    | Requested amount for a dynamic virtual account, when applicable                                                                                                                               |
| `extra`            | object    | Additional channel-specific properties                                                                                                                                                        |
| `meta`             | object    | Optional metadata attached to the payment method                                                                                                                                              |

### Payment Channels

| Channel                | Description                                 |
| ---------------------- | ------------------------------------------- |
| `BANK_ACCOUNT`         | Local bank account transfer                 |
| `MOBILE_MONEY`         | Mobile money wallet (e.g. M-Pesa, MTN MoMo) |
| `SWIFT`                | International SWIFT wire transfer           |
| `INTERAC`              | Interac e-Transfer (Canada)                 |
| `UPI`                  | Unified Payments Interface (India)          |
| `WE_CHAT`              | WeChat Pay                                  |
| `ALIPAY`               | Alipay                                      |
| `CARD`                 | Card payment                                |
| `CRYPTO`               | Crypto rail                                 |
| `VIRTUAL_BANK_ACCOUNT` | Hosted virtual bank account                 |
| `POOL_ACCOUNT`         | Shared pool account for incoming deposits   |
| `ACH_BANK_ACCOUNT`     | US ACH bank transfer                        |
| `PAYBILL_TILL`         | Paybill / Till (M-Pesa business numbers)    |
| `RFP`                  | Request for Payment                         |
| `VIRTUAL_CARD`         | Virtual card                                |

<Note>
  Not every channel is valid when **creating** a payment method. The [Create Payment Method](/api-reference/endpoint/payment-methods/create) endpoint accepts a narrower set of channels; the list above covers all channels that can appear on a returned payment method.
</Note>

### Payment Method Statuses

| Status    | Description                                           |
| --------- | ----------------------------------------------------- |
| `active`  | Payment method is active and usable                   |
| `pending` | Payment method is awaiting activation or verification |
| `deleted` | Payment method has been deleted                       |
| `expired` | Payment method has expired (e.g. an expired card)     |
| `blocked` | Payment method has been blocked                       |

***

## PaymentMethodRecipient

Recipient contact details attached to a payment method, when supplied.

| Field              | Type           | Description                                   |
| ------------------ | -------------- | --------------------------------------------- |
| `recipientName`    | string         | Name of the recipient                         |
| `recipientEmail`   | string (email) | Email address of the recipient                |
| `recipientPhone`   | string         | Phone number of the recipient in E.164 format |
| `recipientAddress` | string         | Address of the recipient                      |

***

## PaymentMethodTransaction

Optional per-transaction details attached to a payment method.

| Field                  | Type   | Description                                        |
| ---------------------- | ------ | -------------------------------------------------- |
| `transactionNarration` | string | Optional reason or description for the transaction |
| `transactionInvoice`   | string | Base64-encoded invoice for the transaction         |

***

## PaymentMethodInstitution

| Field                | Type   | Description                                      |
| -------------------- | ------ | ------------------------------------------------ |
| `institutionId`      | string | Unique ID of the bank or mobile money provider   |
| `institutionName`    | string | Display name of the institution                  |
| `institutionCode`    | string | Institution code (e.g. bank code)                |
| `institutionAddress` | string | Physical address of the institution, if required |

Use the [List Institutions](/api-reference/endpoint/payment-methods/institution) endpoint to retrieve valid institutions for a given country and channel.

***

## Error Response

All API errors return a consistent JSON body:

| Field                     | Type   | Description                                                                                                                                                                                                                       |
| ------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `code`                    | string | Machine-readable error code (e.g. `AUTHENTICATION_ERROR`)                                                                                                                                                                         |
| `error`                   | string | Short error category (e.g. `Bad Request`)                                                                                                                                                                                         |
| `details.errorMessage`    | string | Specific error reason (e.g. `PHONE_COUNTRY_MISMATCH`)                                                                                                                                                                             |
| `details.friendlyMessage` | string | User-friendly message you can display to end users                                                                                                                                                                                |
| `details.data`            | object | Optional caller-safe context. On a customer-create uniqueness conflict (`EMAIL_ALREADY_EXISTS`, `PHONE_NUMBER_ALREADY_EXISTS`) contains `{ customerId }` for the existing customer so you can adopt it without a follow-up lookup |

```json theme={null}
{
  "code": "INVALID_BUSINESS_CUSTOMER_REQUEST",
  "error": "Bad Request",
  "details": {
    "errorMessage": "PHONE_COUNTRY_MISMATCH",
    "friendlyMessage": "The phone number does not match the customer's country."
  }
}
```

### Common error codes

| Code                                | HTTP Status | Description                                                                                                     |
| ----------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------- |
| `AUTHENTICATION_ERROR`              | 401         | API key is missing or invalid                                                                                   |
| `INVALID_BUSINESS_CUSTOMER_REQUEST` | 400         | Customer request validation failed                                                                              |
| `PHONE_COUNTRY_MISMATCH`            | 400         | Phone number country does not match `countryCode`                                                               |
| `EMAIL_ALREADY_EXISTS`              | 409         | A customer with this email already exists. `details.data.customerId` returns the existing customer's id.        |
| `PHONE_NUMBER_ALREADY_EXISTS`       | 409         | A customer with this phone number already exists. `details.data.customerId` returns the existing customer's id. |
| `NOT_FOUND`                         | 404         | The requested resource does not exist                                                                           |
| `RATE_LIMIT_EXCEEDED`               | 429         | Too many requests. Slow down and retry with backoff.                                                            |
