Buy Transaction API Integration Guide (GHS → Stablecoin)
This guide explains how to create, refresh, initiate mobile money payment, verify OTP, and track a GHS on-ramp transaction using the Quidax Ramp API.
An on-ramp transaction allows your customer to pay fiat currency, such as GHS, and receive cryptocurrency, such as USDT, USDC, or cNGN, into their wallet address.
Base URL
https://ramp-be.quidax.io
Transaction Flow
The GHS on-ramp transaction flow works like this:
- Create an on-ramp transaction.
- Refresh the on-ramp transaction if you need to update or recalculate the quote.
- Initiate the customer's GHS mobile money deposit.
- Ask the customer to authorize the mobile money payment.
- If the mobile money provider requires OTP verification, verify the OTP.
- Listen for the
buy_transaction.processingwebhook after the mobile money deposit has been received. - Continue processing while the crypto payout is being prepared.
- Receive the final
buy_transaction.successfulorbuy_transaction.failedwebhook.
Authentication
The Ramp Merchant API uses the x-private-key header for authentication.
Include your merchant private key in each authenticated request:
x-private-key: secret_key
You should also send:
accept: application/json
content-type: application/json
Keep your private key on your backend and do not expose it in frontend or mobile application code.
1. Create an On-Ramp Transaction
This endpoint is used to create an on-ramp transaction.
The merchant_reference should uniquely identify the transaction on the merchant's system.
The customer details and destination wallet are also supplied when creating the transaction.
Endpoint
POST https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/initiate
Request
curl --request POST \
--url https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/initiate \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-private-key: secret_key' \
--data '
{
"from_currency": "ghs",
"to_currency": "usdt",
"from_amount": "2000",
"merchant_reference": "merchant-ghs-momo-0001",
"customer": {
"email": "[email protected]",
"first_name": "test",
"last_name": "user"
},
"wallet_address": {
"address": "0xxx",
"network": "bep20"
}
}
'
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
from_currency | string | Yes | The fiat currency the customer is paying with. For this flow, use ghs. |
to_currency | string | Yes | The cryptocurrency the customer wants to receive. Supported values in the supplied API definition include usdt, usdc, and cngn. |
from_amount | string | Yes | The fiat amount the customer wants to pay. |
merchant_reference | string | Yes | A transaction reference generated by the merchant. |
customer.email | string | Yes | The customer's email address. |
customer.first_name | string | Yes | The customer's first name. The supplied API definition states that this is used for name comparison before approving the deposit. |
customer.last_name | string | Yes | The customer's last name. The supplied API definition states that this is used for name comparison before approving the deposit. |
wallet_address.address | string | Yes | The customer's destination wallet address. |
wallet_address.network | string | Yes | The blockchain network for the destination wallet. Example: bep20. |
Successful Response
HTTP 200
{
"status": "ok",
"message": "Transaction successfully initiated",
"data": {
"public_id": "6a089a1a-7633-4e4c-b6e6-39da723dd4fa",
"reference": "TRX-29U3YLYGC8",
"merchant_reference": "ui79ffjbbnj-fftxnkfffbb12jj345",
"from_currency": "ngn",
"to_currency": "usdt",
"from_amount": "2000.0",
"to_amount": "1.23",
"status": "pending",
"created_at": "2025-05-16T13:17:30.212Z",
"updated_at": "2025-05-16T13:17:33.292Z",
"blockchain_fee": "1.0"
}
}
The supplied response example uses ngn as from_currency. For a GHS transaction, the transaction should correspond to the GHS request created by the merchant.
Successful Response Fields
| Field | Type | Description |
|---|---|---|
status | string | The API response status. ok means the request was successful. |
message | string | A human-readable message describing the result of the request. |
data | object | Contains the transaction details. |
data.public_id | string | The public unique identifier of the on-ramp transaction. |
data.reference | string | The transaction reference generated by Quidax. |
data.merchant_reference | string | The transaction reference provided by the merchant. |
data.from_currency | string | The fiat currency the customer is paying with. |
data.to_currency | string | The cryptocurrency the customer will receive. |
data.from_amount | string | The fiat amount for the transaction. |
data.to_amount | string | The estimated cryptocurrency amount associated with the transaction. |
data.status | string | The current transaction status. pending means the transaction has been created but has not completed. |
data.created_at | string | The date and time the transaction was created. |
data.updated_at | string | The date and time the transaction was last updated. |
data.blockchain_fee | string | The blockchain or network fee applied to the transaction. |
Error Responses
Invalid Amount
HTTP 400
{
"status": "bad_request",
"message": "Invalid amount",
"data": null
}
This response means the submitted transaction amount is invalid.
Invalid Private Key
The supplied OpenAPI definition also includes this response under the HTTP 400 examples.
HTTP 400
{
"status": "forbidden",
"message": "Invalid private key",
"data": null
}
Invalid Address Format
HTTP 400
{
"status": "bad_request",
"message": "Invalid address format",
"data": null
}
This response means the submitted wallet address is invalid.
Invalid Network
HTTP 400
{
"status": "bad_request",
"message": "Invalid network",
"data": null
}
This response means the submitted blockchain network is invalid.
Forbidden
HTTP 403
{
"status": "forbidden",
"message": "Invalid private key",
"data": null
}
This response means the merchant private key is invalid.
2. Refresh an On-Ramp Transaction (Optional)
This endpoint is used to refresh an existing on-ramp transaction.
You must provide the same merchant_reference that was used when initiating the original on-ramp transaction.
Refreshing the transaction can be used to recalculate the quote or update the fiat amount before the customer proceeds with payment.
Endpoint
PUT https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/{merchant_reference}/refresh
Replace {merchant_reference} with the merchant reference used when the transaction was created.
Request
curl --request PUT \
--url https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/merchant-ghs-momo-0001/refresh \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-private-key: secret_key' \
--data '
{
"from_currency": "ghs",
"to_currency": "usdt",
"from_amount": "2000"
}
'
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
from_currency | string | Yes | The fiat currency the customer is paying with. For this flow, use ghs. |
to_currency | string | Yes | The cryptocurrency the customer wants to receive. |
from_amount | string | Yes | The updated fiat amount for the transaction. |
Successful Response
HTTP 200
{
"status": "ok",
"message": "Transaction successfully initiated",
"data": {
"public_id": "6a089a1a-7633-4e4c-b6e6-39da723dd4fa",
"reference": "TRX-29U3YLYGC8",
"merchant_reference": "ui79ffjbbnj-fftxnkfffbb12jj345",
"from_currency": "ngn",
"to_currency": "usdt",
"from_amount": "2000.0",
"to_amount": "1.23",
"status": "pending",
"created_at": "2025-05-16T13:17:30.212Z",
"updated_at": "2025-05-16T13:17:33.292Z",
"blockchain_fee": "1.0"
}
}
Successful Response Fields
| Field | Type | Description |
|---|---|---|
status | string | The API response status. |
message | string | A human-readable message describing the result. |
data | object | Contains the refreshed transaction details. |
data.public_id | string | The public unique identifier of the transaction. |
data.reference | string | The Quidax-generated transaction reference. |
data.merchant_reference | string | The merchant-generated reference associated with the transaction. |
data.from_currency | string | The source fiat currency. |
data.to_currency | string | The destination cryptocurrency. |
data.from_amount | string | The refreshed fiat amount. |
data.to_amount | string | The recalculated cryptocurrency amount. |
data.status | string | The current transaction status. |
data.created_at | string | The transaction creation date and time. |
data.updated_at | string | The transaction's latest update date and time. |
data.blockchain_fee | string | The blockchain fee associated with the transaction. |
Error Responses
Invalid Currency Pair
HTTP 400
{
"status": "bad_request",
"message": "Currency swap not allowed: ngn -> usdtg",
"data": null
}
Failed to Refresh On-Ramp Transaction
HTTP 400
{
"status": "bad_request",
"message": "Failed to refresh on-ramp transaction",
"data": null
}
Invalid Private Key
HTTP 403
{
"status": "forbidden",
"message": "Invalid private key",
"data": null
}
3. Initiate a GHS Mobile Money Deposit
This endpoint is used to initiate the mobile money payment for an existing GHS on-ramp transaction.
The merchant_reference must match the transaction reference used when creating the on-ramp transaction.
Endpoint
POST https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/initiate_mobile_money
Request
curl --request POST \
--url https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/initiate_mobile_money \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-private-key: secret_key' \
--data '
{
"merchant_reference": "merchant-ghs-momo-0001",
"phone_number": "233XXXXXXXXX",
"network_provider": "MTN"
}
'
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
merchant_reference | string | Yes | The transaction reference used when initiating the on-ramp transaction. |
phone_number | string | Yes | The customer's mobile money phone number. |
network_provider | string | Yes | The customer's mobile money provider. Allowed values in the supplied API definition are MTN, AIRTEL, and VODAFONE. |
Successful Response
HTTP 200
{
"status": "ok",
"message": "Mobile money deposit successfully initiated",
"data": {
"next_step": "PIN",
"fee": "23.0",
"amount": "1000.0",
"instruction": "You will receive a prompt on your mobile number ******7778 to enter your PIN to authorize your payment request of GHS 1000 to SB_fjjfjjff",
"currency": "ghs"
}
}
Successful Response Fields
| Field | Type | Description |
|---|---|---|
status | string | The API response status. ok means the request was successful. |
message | string | A human-readable message describing the result. |
data | object | Contains the mobile money payment details. |
data.next_step | string | Indicates the action the customer must perform next. Example: PIN. |
data.fee | string | The fee charged for the mobile money transaction. |
data.amount | string | The GHS amount the customer must authorize. |
data.instruction | string | Instructions explaining what the customer must do to authorize the payment. |
data.currency | string | The mobile money currency. For this flow, this is ghs. |
Handling next_step
next_stepThe application should inspect data.next_step after mobile money initiation.
For example:
{
"next_step": "PIN",
"fee": "23.0",
"amount": "1000.0",
"instruction": "You will receive a prompt on your mobile number ******7778 to enter your PIN to authorize your payment request of GHS 1000 to SB_fjjfjjff",
"currency": "ghs"
}
means the customer must follow the mobile money prompt and enter their PIN.
If the provider requires OTP verification instead, use the Verify Mobile Money OTP endpoint described in the next section.
Error Responses
Mobile Money Deposit Failed
HTTP 400
{
"status": "bad_request",
"message": "Mobile money deposit failed",
"data": null
}
Name Does Not Match
HTTP 400
{
"status": "bad_request",
"message": "Name does not match",
"data": null
}
This response means the customer's name did not match the required payment information.
Invalid Private Key
HTTP 403
{
"status": "forbidden",
"message": "Invalid private key",
"data": null
}
Transaction Does Not Exist
HTTP 404
{
"status": "not_found",
"message": "Transaction does not exist",
"data": null
}
4. Verify Mobile Money OTP
This endpoint is used to verify the OTP for a mobile money deposit.
Use this endpoint when the mobile money provider returns OTP as the next_step. The OTP must be verified before the transaction can continue.
Endpoint
POST https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/verify_mobile_money_otp/
Request
curl --request POST \
--url https://ramp-be.quidax.io/api/v1/merchants/custodial/on_ramp_transactions/verify_mobile_money_otp/ \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-private-key: secret_key' \
--data '
{
"merchant_reference": "merchant-ghs-momo-0001",
"otp": "123456"
}
'
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
merchant_reference | string | Yes | The merchant-generated reference for the existing on-ramp transaction. |
otp | string | Yes | The OTP sent to the customer by the mobile money provider. |
Successful Response
HTTP 200
{
"status": "ok",
"message": "Mobile money deposit verified",
"data": "OTP verified successfully"
}
Successful Response Fields
| Field | Type | Description |
|---|---|---|
status | string | The API response status. ok means the OTP verification request was successful. |
message | string | A human-readable message confirming that the mobile money deposit was verified. |
data | string | Contains the OTP verification result. Example: OTP verified successfully. |
Error Responses
Transaction Not Found
HTTP 400
{
"status": "bad_request",
"message": "Transaction not found",
"data": null
}
This response means the transaction associated with the supplied merchant_reference could not be found.
Fiat Deposit Already Exists
HTTP 400
{
"status": "bad_request",
"message": "Fiat deposit already exists",
"data": null
}
This response means a fiat deposit already exists for the transaction.
Failed to Verify OTP
HTTP 400
{
"status": "bad_request",
"message": "Failed to verify the OTP for your mobile money deposit. Please try again.",
"data": null
}
This response means the OTP could not be verified successfully.
Missing OTP Token
HTTP 400
{
"status": "bad_request",
"message": "Missing OTP token",
"data": null
}
This response means the required OTP token was not supplied.
Deposit Not Found
HTTP 400
{
"status": "bad_request",
"message": "Deposit not found",
"data": null
}
This response means the mobile money deposit associated with the transaction could not be found.
Invalid Private Key
HTTP 403
{
"status": "forbidden",
"message": "Invalid private key",
"data": null
}
This response means the merchant private key supplied in the x-private-key header is invalid.
OTP Integration Notes
- Only call this endpoint when OTP verification is required.
- Use the same
merchant_referenceassociated with the original on-ramp transaction. - Send the OTP exactly as received from the customer.
- A successful HTTP
200response means the OTP was verified. - OTP verification does not mean the full buy transaction has completed.
- Continue listening for webhook events after successful OTP verification.
5. On-Ramp Transaction Webhooks
Webhook notifications are used to track the transaction after the customer authorizes the mobile money payment.
The GHS mobile money flow includes these webhook events:
| Event | Description |
|---|---|
buy_transaction.processing | Sent after the mobile money deposit has been received and the buy transaction is still being processed. |
buy_transaction.successful | Sent when the complete buy transaction has finished successfully. |
buy_transaction.failed | Sent when the buy transaction fails. |
Buy Transaction Processing
This event is dispatched after the customer's mobile money deposit has been received successfully and the buy transaction is still being processed.
At this stage, mobile_money_deposit contains the successful GHS mobile money deposit details.
crypto_payout may still be null because the cryptocurrency payout has not yet been created or completed.
{
"event": "buy_transaction.processing",
"data": {
"public_id": "txn_01JH8MOMO123456789",
"status": "failed",
"mode": "buy",
"from_currency": "ghs",
"to_currency": "usdt",
"from_amount": "250.00",
"to_amount": "15.274321",
"network": "trc20",
"merchant_reference": "merchant-ghs-momo-0001",
"error_message": "We couldn’t complete this right now. Please contact support.",
"blockchain_fee": null,
"crypto_payout": null,
"fiat_deposit": null,
"mobile_money_deposit": {
"public_id": "momo_01JH8MOMO246813579",
"status": "success",
"currency": "ghs",
"amount": "250.00",
"fee": "2.50",
"created_at": "2026-08-15T09:58:42Z",
"updated_at": "2026-08-15T10:02:15Z"
},
"created_at": "2026-08-15T09:57:30Z",
"updated_at": "2026-08-15T10:02:15Z"
}
}
Processing Webhook Fields
| Field | Type | Description |
|---|---|---|
event | string | The webhook event name. For this stage, this is buy_transaction.processing. |
data | object | Contains the buy transaction details. |
data.public_id | string | The public unique identifier of the buy transaction. |
data.status | string | The transaction status returned in the webhook. The supplied sample contains failed. |
data.mode | string | The transaction mode. For this flow, this is buy. |
data.from_currency | string | The fiat currency paid by the customer. Example: ghs. |
data.to_currency | string | The cryptocurrency the customer is purchasing. |
data.from_amount | string | The fiat transaction amount. |
data.to_amount | string | The cryptocurrency amount associated with the transaction. |
data.network | string | The blockchain network selected for the crypto payout. |
data.merchant_reference | string | The merchant-generated transaction reference. |
data.error_message | string or null | Contains an error message when one is associated with the current transaction state. |
data.blockchain_fee | string or null | The blockchain fee associated with the transaction. |
data.crypto_payout | object or null | Contains crypto payout information. It is null in this sample. |
data.fiat_deposit | object or null | Contains standard fiat deposit information where applicable. |
data.mobile_money_deposit | object | Contains the mobile money deposit details. |
data.created_at | string | The date and time the transaction was created. |
data.updated_at | string | The date and time the transaction was last updated. |
Mobile Money Deposit Fields
| Field | Type | Description |
|---|---|---|
data.mobile_money_deposit.public_id | string | The public unique identifier of the mobile money deposit. |
data.mobile_money_deposit.status | string | The status of the mobile money deposit. success means the GHS payment was received successfully. |
data.mobile_money_deposit.currency | string | The mobile money currency. Example: ghs. |
data.mobile_money_deposit.amount | string | The amount received through mobile money. |
data.mobile_money_deposit.fee | string | The fee charged for the mobile money deposit. |
data.mobile_money_deposit.created_at | string | The date and time the mobile money deposit was created. |
data.mobile_money_deposit.updated_at | string | The date and time the mobile money deposit was last updated. |
Do not mark the complete buy transaction as successful when this webhook is received.
The supplied processing example contains data.status: "failed" and an error_message even though the webhook event is buy_transaction.processing and the mobile money deposit has status: "success". These values are preserved exactly as supplied.
Buy Transaction Successful
This event is dispatched when the buy transaction has completed successfully.
At this stage:
- The GHS mobile money deposit has succeeded.
- The crypto payout has completed.
- The overall transaction status is
completed. - A blockchain transaction hash is available.
{
"event": "buy_transaction.successful",
"data": {
"public_id": "txn_01JH8MOMO123456789",
"status": "completed",
"mode": "buy",
"from_currency": "ghs",
"to_currency": "usdt",
"from_amount": "250.00",
"to_amount": "15.274321",
"network": "trc20",
"merchant_reference": "merchant-ghs-momo-0001",
"error_message": null,
"blockchain_fee": "0.50",
"crypto_payout": {
"public_id": "payout_01JH8MOMO987654321",
"transaction_hash": "9f8c7b6a5d4e3f2a1b0c987654321abcd",
"status": "completed",
"amount": "15.274321",
"processor_fee": "0.10",
"address": "TQExampleWalletAddress123456789",
"network": "trc20",
"currency": "usdt",
"created_at": "2026-08-15T10:00:05Z",
"updated_at": "2026-08-15T10:04:21Z"
},
"fiat_deposit": null,
"mobile_money_deposit": {
"public_id": "momo_01JH8MOMO246813579",
"status": "success",
"currency": "ghs",
"amount": "250.00",
"fee": "2.50",
"created_at": "2026-08-15T09:58:42Z",
"updated_at": "2026-08-15T10:00:01Z"
},
"created_at": "2026-08-15T09:57:30Z",
"updated_at": "2026-08-15T10:04:21Z"
}
}
Buy Transaction Failed
This event is dispatched when the buy transaction fails.
{
"event": "buy_transaction.failed",
"data": {
"public_id": "txn_01JH8MOMO123456789",
"status": "failed",
"mode": "buy",
"from_currency": "ghs",
"to_currency": "usdt",
"from_amount": "250.00",
"to_amount": "15.274321",
"network": "trc20",
"merchant_reference": "merchant-ghs-momo-0001",
"error_message": "We couldn’t complete this right now. Please contact support.",
"blockchain_fee": null,
"crypto_payout": null,
"fiat_deposit": null,
"mobile_money_deposit": {
"public_id": "momo_01JH8MOMO246813579",
"status": "failed",
"currency": "ghs",
"amount": "250.00",
"fee": "2.50",
"created_at": "2026-08-15T09:58:42Z",
"updated_at": "2026-08-15T10:02:15Z"
},
"created_at": "2026-08-15T09:57:30Z",
"updated_at": "2026-08-15T10:02:15Z"
}
}
At this stage:
eventisbuy_transaction.failed.data.statusisfailed.error_messagecontains the transaction failure message.crypto_payoutisnull.mobile_money_deposit.statusisfailedin the supplied example.
Webhook Response Fields
Main Payload Fields
| Field | Type | Description |
|---|---|---|
event | string | The webhook event name. Possible values in this flow include buy_transaction.processing, buy_transaction.successful, and buy_transaction.failed. |
data | object | Contains the buy transaction details. |
data.public_id | string | The public unique identifier of the transaction. |
data.status | string | The current transaction status. |
data.mode | string | The transaction mode. For on-ramp transactions, this is buy. |
data.from_currency | string | The fiat currency used for the transaction. |
data.to_currency | string | The cryptocurrency being purchased. |
data.from_amount | string | The fiat amount for the transaction. |
data.to_amount | string | The cryptocurrency amount associated with the transaction. |
data.network | string | The blockchain network used for the crypto payout. |
data.merchant_reference | string | The merchant-generated transaction reference. |
data.error_message | string or null | The transaction error message, if any. |
data.blockchain_fee | string or null | The blockchain fee associated with the transaction. |
data.crypto_payout | object or null | Contains the crypto payout details when available. |
data.fiat_deposit | object or null | Contains standard fiat deposit details where applicable. |
data.mobile_money_deposit | object or null | Contains the mobile money deposit details. |
data.created_at | string | The date and time the transaction was created. |
data.updated_at | string | The date and time the transaction was last updated. |
Crypto Payout Fields
| Field | Type | Description |
|---|---|---|
data.crypto_payout.public_id | string | The public unique identifier of the crypto payout. |
data.crypto_payout.transaction_hash | string | The blockchain transaction hash for the payout. |
data.crypto_payout.status | string | The current status of the crypto payout. |
data.crypto_payout.amount | string | The amount of cryptocurrency sent. |
data.crypto_payout.processor_fee | string | The processor fee charged for the crypto payout. |
data.crypto_payout.address | string | The destination wallet address. |
data.crypto_payout.network | string | The blockchain network used for the payout. |
data.crypto_payout.currency | string | The cryptocurrency sent to the customer. |
data.crypto_payout.created_at | string | The date and time the crypto payout was created. |
data.crypto_payout.updated_at | string | The date and time the crypto payout was last updated. |
Mobile Money Deposit Fields
| Field | Type | Description |
|---|---|---|
data.mobile_money_deposit.public_id | string | The public unique identifier of the mobile money deposit. |
data.mobile_money_deposit.status | string | The current status of the mobile money deposit. |
data.mobile_money_deposit.currency | string | The fiat currency used for the deposit. Example: ghs. |
data.mobile_money_deposit.amount | string | The amount received through mobile money. |
data.mobile_money_deposit.fee | string | The fee charged for the mobile money deposit. |
data.mobile_money_deposit.created_at | string | The date and time the mobile money deposit was created. |
data.mobile_money_deposit.updated_at | string | The date and time the mobile money deposit was last updated. |
Webhook Lifecycle
The GHS mobile money transaction lifecycle works like this:
Create on-ramp transaction
↓
Refresh quote if required
↓
Initiate mobile money deposit
↓
Customer authorizes payment
↓
Verify OTP if required
↓
Mobile money deposit received
↓
buy_transaction.processing
↓
Crypto payout processing
↓
buy_transaction.successful
OR
buy_transaction.failed
When buy_transaction.processing is received, store the mobile money deposit information and continue waiting for the final transaction event.
Do not mark the transaction as completed until the final successful webhook is received.
Important Integration Notes
-
Generate and store a unique
merchant_referencefor each new GHS on-ramp transaction. -
Save the Quidax
public_id,reference, andmerchant_referencereturned after transaction initiation. -
Use the same
merchant_referencewhen refreshing the transaction. -
Use the same
merchant_referencewhen initiating mobile money. -
Use the same
merchant_referencewhen verifying OTP. -
Validate the customer's destination wallet address before creating the transaction.
-
Validate that the selected blockchain network is correct for the destination wallet.
-
Ensure the selected fiat and cryptocurrency pair is supported.
-
Use the customer's correct first and last name because the supplied API definition states that the name is used for comparison before approving the deposit.
-
Initiate mobile money only after the on-ramp transaction has been created.
-
Ensure the correct
network_provideris supplied. The supplied API definition listsMTN,AIRTEL, andVODAFONE. -
Inspect
next_stepafter initiating mobile money. -
If OTP verification is required, call the Verify Mobile Money OTP endpoint.
-
Do not treat successful OTP verification as confirmation that the full buy transaction has completed.
-
Listen for
buy_transaction.processingafter the mobile money deposit has been received. -
A successful
mobile_money_deposit.statusconfirms the mobile money payment, not the completion of the crypto purchase. -
crypto_payoutmay still benullwhen the processing webhook is received. -
Continue listening for
buy_transaction.successfulorbuy_transaction.failed. -
Use
merchant_referenceto match webhook events with the correct internal transaction. -
Store the mobile money deposit
public_id, amount, fee, status, and timestamps for reconciliation. -
Store the crypto payout
public_id, amount, network, address, processor fee, and transaction hash when available. -
Store
error_messagewhen it is returned. -
Treat
buy_transaction.successfulwithdata.status: "completed"as the supplied successful final transaction state. -
Treat
buy_transaction.failedwithdata.status: "failed"as the supplied failed final transaction state. -
The supplied
buy_transaction.processingsample containsdata.status: "failed"and anerror_messageeven thoughmobile_money_deposit.statusissuccess. These values have been preserved exactly as supplied. -
Do not use an HTTP
200response alone to determine whether the complete GHS → stablecoin transaction has finished. -
Use the final transaction webhook to update the customer's order to its completed or failed state.
Updated about 17 hours ago

