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:

  1. Create an on-ramp transaction.
  2. Refresh the on-ramp transaction if you need to update or recalculate the quote.
  3. Initiate the customer's GHS mobile money deposit.
  4. Ask the customer to authorize the mobile money payment.
  5. If the mobile money provider requires OTP verification, verify the OTP.
  6. Listen for the buy_transaction.processing webhook after the mobile money deposit has been received.
  7. Continue processing while the crypto payout is being prepared.
  8. Receive the final buy_transaction.successful or buy_transaction.failed webhook.

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

FieldTypeRequiredDescription
from_currencystringYesThe fiat currency the customer is paying with. For this flow, use ghs.
to_currencystringYesThe cryptocurrency the customer wants to receive. Supported values in the supplied API definition include usdt, usdc, and cngn.
from_amountstringYesThe fiat amount the customer wants to pay.
merchant_referencestringYesA transaction reference generated by the merchant.
customer.emailstringYesThe customer's email address.
customer.first_namestringYesThe customer's first name. The supplied API definition states that this is used for name comparison before approving the deposit.
customer.last_namestringYesThe customer's last name. The supplied API definition states that this is used for name comparison before approving the deposit.
wallet_address.addressstringYesThe customer's destination wallet address.
wallet_address.networkstringYesThe 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

FieldTypeDescription
statusstringThe API response status. ok means the request was successful.
messagestringA human-readable message describing the result of the request.
dataobjectContains the transaction details.
data.public_idstringThe public unique identifier of the on-ramp transaction.
data.referencestringThe transaction reference generated by Quidax.
data.merchant_referencestringThe transaction reference provided by the merchant.
data.from_currencystringThe fiat currency the customer is paying with.
data.to_currencystringThe cryptocurrency the customer will receive.
data.from_amountstringThe fiat amount for the transaction.
data.to_amountstringThe estimated cryptocurrency amount associated with the transaction.
data.statusstringThe current transaction status. pending means the transaction has been created but has not completed.
data.created_atstringThe date and time the transaction was created.
data.updated_atstringThe date and time the transaction was last updated.
data.blockchain_feestringThe 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

FieldTypeRequiredDescription
from_currencystringYesThe fiat currency the customer is paying with. For this flow, use ghs.
to_currencystringYesThe cryptocurrency the customer wants to receive.
from_amountstringYesThe 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

FieldTypeDescription
statusstringThe API response status.
messagestringA human-readable message describing the result.
dataobjectContains the refreshed transaction details.
data.public_idstringThe public unique identifier of the transaction.
data.referencestringThe Quidax-generated transaction reference.
data.merchant_referencestringThe merchant-generated reference associated with the transaction.
data.from_currencystringThe source fiat currency.
data.to_currencystringThe destination cryptocurrency.
data.from_amountstringThe refreshed fiat amount.
data.to_amountstringThe recalculated cryptocurrency amount.
data.statusstringThe current transaction status.
data.created_atstringThe transaction creation date and time.
data.updated_atstringThe transaction's latest update date and time.
data.blockchain_feestringThe 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

FieldTypeRequiredDescription
merchant_referencestringYesThe transaction reference used when initiating the on-ramp transaction.
phone_numberstringYesThe customer's mobile money phone number.
network_providerstringYesThe 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

FieldTypeDescription
statusstringThe API response status. ok means the request was successful.
messagestringA human-readable message describing the result.
dataobjectContains the mobile money payment details.
data.next_stepstringIndicates the action the customer must perform next. Example: PIN.
data.feestringThe fee charged for the mobile money transaction.
data.amountstringThe GHS amount the customer must authorize.
data.instructionstringInstructions explaining what the customer must do to authorize the payment.
data.currencystringThe mobile money currency. For this flow, this is ghs.

Handling next_step

The 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

FieldTypeRequiredDescription
merchant_referencestringYesThe merchant-generated reference for the existing on-ramp transaction.
otpstringYesThe 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

FieldTypeDescription
statusstringThe API response status. ok means the OTP verification request was successful.
messagestringA human-readable message confirming that the mobile money deposit was verified.
datastringContains 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

  1. Only call this endpoint when OTP verification is required.
  2. Use the same merchant_reference associated with the original on-ramp transaction.
  3. Send the OTP exactly as received from the customer.
  4. A successful HTTP 200 response means the OTP was verified.
  5. OTP verification does not mean the full buy transaction has completed.
  6. 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:

EventDescription
buy_transaction.processingSent after the mobile money deposit has been received and the buy transaction is still being processed.
buy_transaction.successfulSent when the complete buy transaction has finished successfully.
buy_transaction.failedSent 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

FieldTypeDescription
eventstringThe webhook event name. For this stage, this is buy_transaction.processing.
dataobjectContains the buy transaction details.
data.public_idstringThe public unique identifier of the buy transaction.
data.statusstringThe transaction status returned in the webhook. The supplied sample contains failed.
data.modestringThe transaction mode. For this flow, this is buy.
data.from_currencystringThe fiat currency paid by the customer. Example: ghs.
data.to_currencystringThe cryptocurrency the customer is purchasing.
data.from_amountstringThe fiat transaction amount.
data.to_amountstringThe cryptocurrency amount associated with the transaction.
data.networkstringThe blockchain network selected for the crypto payout.
data.merchant_referencestringThe merchant-generated transaction reference.
data.error_messagestring or nullContains an error message when one is associated with the current transaction state.
data.blockchain_feestring or nullThe blockchain fee associated with the transaction.
data.crypto_payoutobject or nullContains crypto payout information. It is null in this sample.
data.fiat_depositobject or nullContains standard fiat deposit information where applicable.
data.mobile_money_depositobjectContains the mobile money deposit details.
data.created_atstringThe date and time the transaction was created.
data.updated_atstringThe date and time the transaction was last updated.

Mobile Money Deposit Fields

FieldTypeDescription
data.mobile_money_deposit.public_idstringThe public unique identifier of the mobile money deposit.
data.mobile_money_deposit.statusstringThe status of the mobile money deposit. success means the GHS payment was received successfully.
data.mobile_money_deposit.currencystringThe mobile money currency. Example: ghs.
data.mobile_money_deposit.amountstringThe amount received through mobile money.
data.mobile_money_deposit.feestringThe fee charged for the mobile money deposit.
data.mobile_money_deposit.created_atstringThe date and time the mobile money deposit was created.
data.mobile_money_deposit.updated_atstringThe 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:

  • event is buy_transaction.failed.
  • data.status is failed.
  • error_message contains the transaction failure message.
  • crypto_payout is null.
  • mobile_money_deposit.status is failed in the supplied example.

Webhook Response Fields

Main Payload Fields

FieldTypeDescription
eventstringThe webhook event name. Possible values in this flow include buy_transaction.processing, buy_transaction.successful, and buy_transaction.failed.
dataobjectContains the buy transaction details.
data.public_idstringThe public unique identifier of the transaction.
data.statusstringThe current transaction status.
data.modestringThe transaction mode. For on-ramp transactions, this is buy.
data.from_currencystringThe fiat currency used for the transaction.
data.to_currencystringThe cryptocurrency being purchased.
data.from_amountstringThe fiat amount for the transaction.
data.to_amountstringThe cryptocurrency amount associated with the transaction.
data.networkstringThe blockchain network used for the crypto payout.
data.merchant_referencestringThe merchant-generated transaction reference.
data.error_messagestring or nullThe transaction error message, if any.
data.blockchain_feestring or nullThe blockchain fee associated with the transaction.
data.crypto_payoutobject or nullContains the crypto payout details when available.
data.fiat_depositobject or nullContains standard fiat deposit details where applicable.
data.mobile_money_depositobject or nullContains the mobile money deposit details.
data.created_atstringThe date and time the transaction was created.
data.updated_atstringThe date and time the transaction was last updated.

Crypto Payout Fields

FieldTypeDescription
data.crypto_payout.public_idstringThe public unique identifier of the crypto payout.
data.crypto_payout.transaction_hashstringThe blockchain transaction hash for the payout.
data.crypto_payout.statusstringThe current status of the crypto payout.
data.crypto_payout.amountstringThe amount of cryptocurrency sent.
data.crypto_payout.processor_feestringThe processor fee charged for the crypto payout.
data.crypto_payout.addressstringThe destination wallet address.
data.crypto_payout.networkstringThe blockchain network used for the payout.
data.crypto_payout.currencystringThe cryptocurrency sent to the customer.
data.crypto_payout.created_atstringThe date and time the crypto payout was created.
data.crypto_payout.updated_atstringThe date and time the crypto payout was last updated.

Mobile Money Deposit Fields

FieldTypeDescription
data.mobile_money_deposit.public_idstringThe public unique identifier of the mobile money deposit.
data.mobile_money_deposit.statusstringThe current status of the mobile money deposit.
data.mobile_money_deposit.currencystringThe fiat currency used for the deposit. Example: ghs.
data.mobile_money_deposit.amountstringThe amount received through mobile money.
data.mobile_money_deposit.feestringThe fee charged for the mobile money deposit.
data.mobile_money_deposit.created_atstringThe date and time the mobile money deposit was created.
data.mobile_money_deposit.updated_atstringThe 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

  1. Generate and store a unique merchant_reference for each new GHS on-ramp transaction.

  2. Save the Quidax public_id, reference, and merchant_reference returned after transaction initiation.

  3. Use the same merchant_reference when refreshing the transaction.

  4. Use the same merchant_reference when initiating mobile money.

  5. Use the same merchant_reference when verifying OTP.

  6. Validate the customer's destination wallet address before creating the transaction.

  7. Validate that the selected blockchain network is correct for the destination wallet.

  8. Ensure the selected fiat and cryptocurrency pair is supported.

  9. 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.

  10. Initiate mobile money only after the on-ramp transaction has been created.

  11. Ensure the correct network_provider is supplied. The supplied API definition lists MTN, AIRTEL, and VODAFONE.

  12. Inspect next_step after initiating mobile money.

  13. If OTP verification is required, call the Verify Mobile Money OTP endpoint.

  14. Do not treat successful OTP verification as confirmation that the full buy transaction has completed.

  15. Listen for buy_transaction.processing after the mobile money deposit has been received.

  16. A successful mobile_money_deposit.status confirms the mobile money payment, not the completion of the crypto purchase.

  17. crypto_payout may still be null when the processing webhook is received.

  18. Continue listening for buy_transaction.successful or buy_transaction.failed.

  19. Use merchant_reference to match webhook events with the correct internal transaction.

  20. Store the mobile money deposit public_id, amount, fee, status, and timestamps for reconciliation.

  21. Store the crypto payout public_id, amount, network, address, processor fee, and transaction hash when available.

  22. Store error_message when it is returned.

  23. Treat buy_transaction.successful with data.status: "completed" as the supplied successful final transaction state.

  24. Treat buy_transaction.failed with data.status: "failed" as the supplied failed final transaction state.

  25. The supplied buy_transaction.processing sample contains data.status: "failed" and an error_message even though mobile_money_deposit.status is success. These values have been preserved exactly as supplied.

  26. Do not use an HTTP 200 response alone to determine whether the complete GHS → stablecoin transaction has finished.

  27. Use the final transaction webhook to update the customer's order to its completed or failed state.


Did this page help you?