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

# Integration

This guide covers the three parts of an instant payment integration:

1. [Manage your aliases](#manage-your-aliases) (live mode only).
2. [Collect an instant payment](#collect-an-instant-payment).
3. [Send an instant payment](#send-an-instant-payment).

Read the [introduction](https://docs.hub2.io/integration/en/instant_payment/instant_payment_introduction.md) first for the concepts and the prerequisites: instant payment must be enabled for your merchant account by HUB2, and your API key must hold the alias permissions for the alias endpoints.

***

## Manage your aliases

[HUB2 API reference - List aliases](https://docs.hub2.io/api-reference/instant-payment/list-aliases.md)

[HUB2 API reference - Create an alias](https://docs.hub2.io/api-reference/instant-payment/create-an-alias.md)

[HUB2 API reference - Delete an alias](https://docs.hub2.io/api-reference/instant-payment/delete-an-alias.md)

The three alias endpoints address one of your accounts through the `accountType` path parameter: `collection` (receives instant payments) or `transfer` (pays them out). They only work in live mode: in sandbox they are refused with a `403` error (`instant_payment_live_only`).

### List the aliases of an account

The list contains every alias the directory holds for the account, including the primary alias registered by HUB2.

```bash Curl theme={null}
curl --location --request GET 'https://api.hub2.io/instant-payment/accounts/collection/aliases' \
--header 'ApiKey: [REDACTED]' \
--header 'MerchantId: [REDACTED]' \
--header 'Environment: live'
```

```json theme={null}
[
    {
        "aliasKey": "b9a4c2e1-7f3d-4e5a-9c8b-1d2e3f4a5b6c",
        "aliasType": "SHID",
        "accountType": "collection",
        "isPrimary": true
    }
]
```

`aliasKey` is the value to publish so that payers can reach your account, and the value to send as `payeeAlias` when you attempt a payment.

### Create an alias

```bash Curl theme={null}
curl --location --request POST 'https://api.hub2.io/instant-payment/accounts/collection/aliases' \
--header 'ApiKey: [REDACTED]' \
--header 'MerchantId: [REDACTED]' \
--header 'Environment: live'
```

The request has no body: the directory generates the `SHID` key. An account holds one `SHID` alias, so when the account already has one, the API responds with `201` and returns that alias with `created` set to `false` instead of creating a second one. Retrying a creation is therefore always safe.

```json theme={null}
{
    "aliasKey": "b9a4c2e1-7f3d-4e5a-9c8b-1d2e3f4a5b6c",
    "aliasType": "SHID",
    "accountType": "collection",
    "isPrimary": true,
    "created": false
}
```

### Delete an alias

```bash Curl theme={null}
curl --location --request DELETE 'https://api.hub2.io/instant-payment/accounts/collection/aliases/b9a4c2e1-7f3d-4e5a-9c8b-1d2e3f4a5b6c' \
--header 'ApiKey: [REDACTED]' \
--header 'MerchantId: [REDACTED]' \
--header 'Environment: live'
```

The API responds with `204 No Content`. From then on, payers can no longer reach your account through this alias and HUB2 no longer accepts it as your own alias on a payment.

* The primary alias registered by HUB2 cannot be deleted: the request is refused with a `409` error (`instant_payment_primary_alias_protected`). Contact HUB2 Support to retire it.
* An alias that is not yours is refused exactly like an alias that does not exist, with a `403` error (`instant_payment_alias_not_owned`).

### Alias errors

| Status | Code | Meaning |
| :- | :- | :- |
| `403` | `instant_payment_live_only` | The request was sent in sandbox mode. Alias management is available in live mode only. |
| `403` | `instant_payment_not_enabled_for_merchant` | Instant payment is not enabled for your merchant account. Contact HUB2 Support. |
| `403` | `group_owner_transaction_forbidden` | A parent merchant tried to create or delete an alias under its own `MerchantId`. Use the submerchant `MerchantId`. |
| `403` | `missing_permission` | The API key does not hold the permission required by the endpoint. |
| `403` | `instant_payment_alias_not_owned` | The alias does not exist or is not registered to your merchant account. |
| `409` | `instant_payment_account_not_enrolled` | The account is not enrolled for instant payment yet. Contact HUB2 Support. |
| `409` | `instant_payment_primary_alias_protected` | The alias is the primary alias registered by HUB2 and cannot be deleted through the API. |
| `409` | `instant_payment_alias_deactivated` | HUB2 deactivated the alias of this account. Only HUB2 Support can restore it. |
| `422` | `instant_payment_alias_refused` | The directory refused the operation. Nothing was changed. |
| `422` | `instant_payment_account_missing` | Your merchant account has no live account of the requested type. |
| `422` | `instant_payment_participant_not_served` | Instant payment is not available in your country. |
| `502` | `instant_payment_alias_not_recorded` | The directory registered the alias but HUB2 could not record it. Retry the request. |
| `502` | `instant_payment_alias_deletion_not_recorded` | The directory removed the alias but HUB2 could not record the removal. Retry the request. |
| `502` | `instant_payment_alias_divergence` | The directory and HUB2 disagree about this alias. Nothing was recorded. Contact HUB2 Support. |
| `503` | `instant_payment_alias_rail_unavailable` | The directory is unavailable. Retry later: a retry never creates a second alias. |

***

## Collect an instant payment

A collection follows the [payment integration](https://docs.hub2.io/integration/en/payments/payments_integration.md): you create a payment intent, attempt a payment on it, then follow its status. Only the payment attempt differs for instant payment. The payment intent must be in `XOF`.

### Get the fees

[HUB2 API reference - Retrieve fees](https://docs.hub2.io/api-reference/payments/retrieve-fees.md)

To display the fees before the customer pays, call the fees endpoint of the payment intent with `paymentMethod=instant_payment` and the `country`. The `provider` parameter is not required for instant payment, which has a single provider. If you send it, it is ignored.

```bash Curl theme={null}
curl --location --request GET 'https://api.hub2.io/payment-intents/pi_tffiDaXyWQu203rIXhujW/payment-fees?paymentMethod=instant_payment&country=CI' \
--header 'ApiKey: [REDACTED]' \
--header 'MerchantId: [REDACTED]' \
--header 'Environment: live'
```

### Attempt the payment

[HUB2 API reference - Attempt a payment](https://docs.hub2.io/api-reference/payments/attempt-a-payment-on-a-paymentintent-object.md)

Attempt a payment on the payment intent with the payment method `instant_payment`.

```bash Curl theme={null}
curl --location --request POST 'https://api.hub2.io/payment-intents/pi_tffiDaXyWQu203rIXhujW/payments' \
--header 'Content-Type: application/json' \
--data-raw '{
    "token": "<PAYMENT_INTENT_TOKEN>",
    "paymentMethod": "instant_payment",
    "country": "CI",
    "instantPayment": {
        "payerAlias": "+2250700000001",
        "payeeAlias": "b9a4c2e1-7f3d-4e5a-9c8b-1d2e3f4a5b6c"
    }
}'
```

| Field | Required | Description |
| :- | :-: | :- |
| `paymentMethod` | Yes | `instant_payment`. |
| `country` | Yes | `CI` or `SN`. It selects the national participant that serves the transaction and must match the country of your own alias. |
| `instantPayment.payerAlias` | Yes | The alias of the customer's account: a `SHID` key, a merchant code or a mobile number in E.164 format. 64 characters at most. |
| `instantPayment.payeeAlias` | Yes | One of your own active collection aliases (`SHID` or `MCOD`): the account that receives the funds. 64 characters at most. |

There is no `provider` field and no `mobileMoney` object. Both aliases are stated on every request and are never trimmed or normalized: send them exactly as stored.

HUB2 checks everything it can before the request reaches the rail, because a payment sent on the rail cannot be recalled:

* the country is served, and instant payment is enabled for your merchant account;
* `payeeAlias` is well formed and is one of your active collection aliases. An alias registered to another merchant, or to nobody, is refused in the same way (`403`, `instant_payment_alias_not_owned`);
* `payerAlias` is well formed. HUB2 does not check that it exists: the rail answers that, and a payer alias that does not exist makes the payment fail.

### Follow the payment

The payment is created in `created` status, then stays `pending` while the rail processes it, and the payment intent is `processing`. The outcome comes from the rail and updates the payment to `successful` or `failed`, with a `failure` object that holds the failure cause.

Use [webhooks](https://docs.hub2.io/integration/en/webhooks/webhooks_overview.md) to follow the outcome, as for any other payment method. If you cannot, poll the [payment intent status](https://docs.hub2.io/api-reference/payments/retrieve-a-paymentintent-status.md) only while the status is `processing`.

When HUB2 cannot tell whether the rail received a request, the payment stays `pending` instead of being failed. Do not create a second payment for the same purchase in that case: wait for the webhook or read the status.

### Payment errors

| Status | Code or message | Meaning |
| :- | :- | :- |
| `400` | `Instant payment details are required when payment method is set to "instant_payment".` | The `instantPayment` object is missing. |
| `400` | `payeeAlias is not a valid instant payment alias.` or `payerAlias is not a valid instant payment alias.` | The value matches none of the alias types. The message names the faulty field. |
| `400` | `payeeAlias must be a SHID or MCOD alias: a merchant account cannot hold a mobile-number alias.` | Your own alias cannot be a mobile number. |
| `400` | `payeeAlias is not enrolled on the participant serving this country.` | The `country` does not match the country of your alias. |
| `400` | `Instant payment is not available in this country. Supported: CI, SN.` | The `country` is not served. |
| `403` | `instant_payment_not_enabled_for_merchant` | Instant payment is not enabled for your merchant account. |
| `403` | `instant_payment_alias_not_owned` | `payeeAlias` is not an active collection alias of your merchant account. |

***

## Send an instant payment

[HUB2 API reference - Create a transfer](https://docs.hub2.io/api-reference/transfers/create-transfer.md)

A transfer follows the [transfer integration](https://docs.hub2.io/integration/en/transfers/transfers_integration.md). For instant payment, set the destination type to `instant_payment` and send the alias of the beneficiary. The currency must be `XOF`.

```bash Curl theme={null}
curl --location --request POST 'https://api.hub2.io/transfers' \
--header 'ApiKey: [REDACTED]' \
--header 'MerchantId: [REDACTED]' \
--header 'Environment: live' \
--header 'Content-Type: application/json' \
--data-raw '{
  "reference": "<YOUR_INTERNAL_REFERENCE>",
  "amount": 2000,
  "currency": "XOF",
  "description": "<YOUR_DESCRIPTION>",
  "destination": {
    "type": "instant_payment",
    "country": "CI",
    "recipientName": "John Doe",
    "payeeAlias": "+2250700000001"
  }
}'
```

| Field | Required | Description |
| :- | :-: | :- |
| `destination.type` | Yes | `instant_payment`. |
| `destination.country` | Yes | `CI` or `SN`. |
| `destination.payeeAlias` | Yes | The beneficiary's alias: a `SHID` key, a merchant code or a mobile number in E.164 format. 64 characters at most. |
| `destination.recipientName` | No | The name of the beneficiary. |

There is no payer alias in the request. The account debited is always your own transfer account, and HUB2 selects the alias to use among the aliases registered on it, the primary one first. The response returns the `payerAlias` used and the `payeeAlias` you sent in the `destination` object, together with `provider` set to `pispi`.

If your transfer account has no active alias, the transfer is refused with a `400` error. As for a payment, HUB2 only checks the shape of the beneficiary's alias: a beneficiary alias that does not exist makes the transfer fail.

A transfer goes through the usual statuses (`created`, `pending`, then `successful` or `failed`). Follow it with [webhooks](https://docs.hub2.io/integration/en/webhooks/webhooks_overview.md), as for the other destinations. When HUB2 cannot tell whether the rail received the request, the transfer stays `pending`: do not create a second transfer for the same beneficiary, wait for the webhook or read the status.

### Transfer errors

| Status | Code or message | Meaning |
| :- | :- | :- |
| `400` | `destination.payeeAlias is not a valid instant payment alias.` | The beneficiary alias matches none of the alias types. |
| `400` | `Instant payment is not available in this country. Supported: CI, SN.` | The `destination.country` is not served. |
| `400` | `No active instant payment alias is registered for this merchant's transfer account.` | Your transfer account has no active alias. Contact HUB2 Support. |
| `403` | `instant_payment_not_enabled_for_merchant` | Instant payment is not enabled for your merchant account. |

***

## Failure causes

When a payment or a transfer fails, the `failure.code` field gives the cause. The failure causes of the rail are translated as follows:

| Cause on a payment | Cause on a transfer | Meaning |
| :- | :- | :- |
| `customer_insufficient_funds` | `insufficient_funds` | The debited account does not hold enough funds. |
| `customer_account_locked` | `forbidden_by_provider` | The account cannot accept the movement (blocked or closed). |
| `bad_parameters` | `bad_parameters` | The instruction is wrong: an alias or an account does not check out. |
| `forbidden_by_provider` | `forbidden_by_provider` | The rail or a regulation refused the transaction. |
| `invalid_amount` | `invalid_amount` | The amount is refused. |
| `duplicate_request` | `duplicate_request` | The rail already holds a transaction with this identifier. |
| `canceled_by_customer` | `canceled` | The transaction was withdrawn by one of the parties. |
| `canceled` | `canceled` | The transaction was canceled. |
| `fraud_suspicion` | `fraud_suspicion` | A suspected fraud was detected. |
| `service_unavailable` | `service_unavailable` | A participant or the rail is unavailable. A new attempt can succeed. |
| `unknown_reason` | `unknown_reason` | The rail gave no reason, or a reason HUB2 does not map yet. |

See also the complete lists of [payment failure causes](https://docs.hub2.io/integration/en/payments/payments_failure_causes.md) and [transfer failure causes](https://docs.hub2.io/integration/en/transfers/transfers_failure_causes.md).

***

## Sandbox

In sandbox mode, no request reaches the rail: HUB2 simulates the outcome from the last 8 characters of the counterparty alias, which is the `payerAlias` of a payment and the `payeeAlias` of a transfer. The alias must still be well formed, for example `+22500000001`, and the country must be `CI` or `SN`.

Your own aliases are still checked in sandbox: the `payeeAlias` of a payment must be a collection alias of your merchant account, and a transfer needs an alias on your transfer account. Aliases cannot be created in sandbox, so list them beforehand in live mode (see [Manage your aliases](#manage-your-aliases)) and reuse them in sandbox.

### Payments

| Last 8 characters of `payerAlias` | Status | Failure cause |
| :-: | :- | :- |
| `00000001` | successful | |
| `00000002` | successful (with delay) | |
| `00000003` | pending (never completes) | |
| `00000101` | failed | `customer_insufficient_funds` |
| `00000102` | failed | `bad_parameters` |
| `00000103` | failed | `customer_account_locked` |
| `00000104` | failed | `canceled_by_customer` |
| `00000105` | failed | `fraud_suspicion` |
| `00000500` | failed | `service_unavailable` |

Any other value makes the payment fail with `bad_parameters`.

### Transfers

| Last 8 characters of `payeeAlias` | Status | Failure cause |
| :-: | :- | :- |
| `00000001` | successful | |
| `00000002` | successful (with delay) | |
| `00000003` | pending (never completes) | |
| `00000101` | failed | `insufficient_funds` |
| `00000102` | failed | `bad_parameters` |
| `00000103` | failed | `forbidden_by_provider` |
| `00000104` | failed | `canceled` |
| `00000105` | failed | `fraud_suspicion` |
| `00000500` | failed | `service_unavailable` |

Any other value makes the transfer fail with `invalid_destination`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.