{
"grant_type": "client_credentials",
"client_id": "fex_…",
"client_secret": "…"
}
{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 1200
}
Partner API Product guide
Xoxoday e-gift vouchers, experiences and physical vouchers, plus MojoLife gift cards, vouchers and deals, for Ghana, billed in GHS.
http://fex.mojo-pay.com/v1
Everything you need to sell rewards through the FEX Partner API. All paths are relative to the /v1 base URL above. Shared concepts (sandbox vs live, rate limits) are on the Partner API overview.
POST /oauth/token.GET /providers/PRV_XOXODAY/vouchers?product_code=xo-gift-voucher, or MojoLife SKUs with GET /providers/PRV_MOJOLIFE/vouchers?product_code=ml-gift-card (or ml-voucher).product_id and the receiver’s email. Xoxoday also needs a face-value denomination and contact.payment.url (always billed in GHS).order.completed. Xoxoday delivers the voucher to the receiver; MojoLife returns the code in provider_details.voucher_code.ml-deal) are paid on the MojoLife checkout: payment.method is provider_checkout and the confirmation code arrives with order.completed.| Product | Name | Provider | Required fields | Lookup |
|---|---|---|---|---|
PRD_ML_DEALml-deal |
MojoLife Deals | MojoLife | product_id buyer_name email |
— |
PRD_PPN_GIFT_CARDppn-gift-card |
International Gift Card | FEX | sku_id amount email |
Yes |
PRD_ML_GIFT_CARDml-gift-card |
MojoLife Gift Card | MojoLife | product_id email |
— |
PRD_ML_VOUCHERml-voucher |
MojoLife Voucher | MojoLife | product_id email |
— |
PRD_XO_GIFT_VOUCHERxo-gift-voucher |
Xoxoday E-Gift Voucher | Xoxoday Canvas | product_id denomination email contact |
— |
PRD_XO_EXPERIENCExo-experience |
Xoxoday Experience | Xoxoday Canvas | product_id denomination email contact |
— |
PRD_XO_PHYSICALxo-physical-voucher |
Xoxoday Physical Voucher | Xoxoday Canvas | product_id denomination email contact |
— |
Orientation only — your credentials see a partner-scoped subset. Always call GET /catalog/products and read each input_schema rather than hardcoding this table.
Create a client_id / client_secret under Partner Portal → API credentials, then exchange them for a Bearer token (about 20 minutes). Send Authorization: Bearer <token> on every other call.
| Header | Required | Description |
|---|---|---|
Authorization |
Yes* | Bearer <token> (*except token endpoint) |
Content-Type |
POST | application/json |
Accept |
Recommended | application/json |
X-FEX-Country |
No | ISO country (e.g. GH). Defaults to partner profile. |
Idempotency-Key |
Recommended | On POST /orders — replay-safe create. |
{
"grant_type": "client_credentials",
"client_id": "fex_…",
"client_secret": "…"
}
{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 1200
}
Xoxoday Plum rewards for Ghana only: e-gift vouchers, experiences, and physical vouchers. FEX catalog products are umbrellas: xo-gift-voucher, xo-experience, xo-physical-voucher (under gift_cards). Brand SKUs come from GET /providers/{id}/vouchers?product_code=xo-gift-voucher (always Ghana). Then quote the matching FEX product with Plum product_id + native denomination (SKU face currency) + receiver email/contact. Quotes and MojoPay always bill GHS — FEX converts foreign face values using Admin → Settings → FX rates (rate + markup). Provider id: PRV_XOXODAY / xoxoday.
GET /providers/{id}/vouchers
Authorization: Bearer <token>
{
"object": "provider_voucher_list",
"provider_id": "PRV_XOXODAY",
"provider_code": "xoxoday",
"product_category": "e-gift voucher",
"product_code": "xo-gift-voucher",
"country": "ghana",
"limit": 50,
"page": 1,
"count": 2,
"total": null,
"has_more": false,
"vouchers": [
{
"id": "54514",
"name": "Apple Gift Card",
"currency": "USD",
"product_category": "e-gift voucher",
"min_denomination": 10,
"max_denomination": 500,
"ghs_min_denomination": "155.00",
"ghs_max_denomination": "7750.00",
"ghs_rate": "15.5",
"fx_markup_percent": "0",
"fx_status": "ok",
"country": "Ghana",
"image_url": "https://…",
"provider_details": {}
}
]
}
GET /providers/{id}/voucher-filters
Authorization: Bearer <token>
GET /providers/{id}/order-history
Authorization: Bearer <token>
GET /providers/{id}/payment-report
Authorization: Bearer <token>
MojoLife gift cards (stored value, redeemable across MojoLife merchants) and vouchers (redeemable, including partially, at participating merchants) for Ghana. FEX products: ml-gift-card and ml-voucher (under gift_cards). List SKUs, quote with the SKU product_id and the receiver email, then create the order. SKUs are priced in GHS, so no FX applies. When the order completes, the code is returned in provider_details.voucher_code, both on the order and in the order.completed webhook. Deals (ml-deal, under deals) are event tickets, experiences and offers; the buyer pays MojoLife directly (see below). Provider id: PRV_MOJOLIFE / mojolife.
Quote request (POST /quotes). For vouchers, the voucher is assigned to email, and the holder must present that email when redeeming. Gift cards also accept optional recipient_name and message.
{
"product_id": "PRD_ML_GIFT_CARD",
"fields": {
"product_id": "0c895be8-bc97-4489-9ad4-cffecc96295a",
"email": "receiver@example.com",
"recipient_name": "Ama",
"message": "Happy birthday!"
}
}
Completed order (GET /orders/{id} or the order.completed webhook)
{
"id": "ORD_…",
"object": "order",
"status": "completed",
"currency": "GHS",
"amount_payable": "25.00",
"product_id": "PRD_ML_GIFT_CARD",
"provider_reference": "9b1f…",
"provider_details": {
"voucher_code": "MLGC-7Q4K-P2ZD",
"voucher_type": "gift_card",
"voucher_value": "25.00",
"voucher_currency": "GHS",
"voucher_expires_at": "2027-09-26T18:00:00+00:00"
}
}
Deals are paid on MojoLife. Quote PRD_ML_DEAL with the deal product_id (id or slug), buyer_name, email, optional phone and quantity (1–20). The quote is the live price × quantity. When you create the order, payment.method is provider_checkout and payment.url is the MojoLife checkout page: send the buyer there. After they pay, the order goes straight to completed (order.paid then order.completed) with the confirmation code in provider_details.voucher_code (voucher_type deal). Free deals complete as soon as the order is created. Unpaid checkouts fail with payment_expired after 24 hours, and these orders cannot be cancelled through FEX. payment_method collection is not supported.
{
"product_id": "PRD_ML_DEAL",
"fields": {
"product_id": "f1d4c2a0-…",
"buyer_name": "Ama Mensah",
"email": "ama@example.com",
"phone": "0241234567",
"quantity": 2
}
}
GET /providers/{id}/vouchers
Authorization: Bearer <token>
{
"object": "provider_voucher_list",
"provider_id": "PRV_MOJOLIFE",
"provider_code": "mojolife",
"product_code": "ml-gift-card",
"country": "ghana",
"count": 1,
"has_more": false,
"vouchers": [
{
"id": "0c895be8-bc97-4489-9ad4-cffecc96295a",
"name": "MojoLife ₵25 Gift Card",
"description": "Spend on lifestyle experiences across MojoLife.",
"fex_product_code": "ml-gift-card",
"currency": "GHS",
"face_value": "25.00",
"price": "25.00",
"validity_days": 365,
"seller": null,
"country": "Ghana",
"image_url": "https://life.mojolabx.com/images/native/gift-card.png"
}
]
}
A quote locks the price for the fields you send. Every field must satisfy the product input_schema.
{
"product_id": "PRD_XO_GIFT_VOUCHER",
"fields": {
"product_id": "54514",
"denomination": 10,
"quantity": 1,
"email": "receiver@example.com",
"contact": "0245885885"
}
}
{
"id": "QTE_…",
"object": "quote",
"product_id": "PRD_XO_GIFT_VOUCHER",
"currency": "GHS",
"amount": "155.00",
"amount_payable": "155.00",
"fx": {
"face_currency": "USD",
"face_denomination": 10,
"face_amount": 10,
"quantity": 1,
"rate_to_ghs": "15.5",
"markup_percent": "0",
"amount_ghs": "155.00"
},
"expires_at": "2026-08-30T15:00:00+00:00"
}
GET /quotes/{id}
Authorization: Bearer <token>
Lifecycle: pending_payment → paid → fulfilling → completed (or failed / cancelled / expired). After payment FEX places the Xoxoday order and the voucher is delivered to the receiver’s email / phone. MojoLife codes are issued immediately and the order completes with provider_details.voucher_code. MojoLife deals complete once the buyer pays on the MojoLife checkout.
{
"quote_id": "QTE_…",
"partner_reference": "INV-1001",
"payment_method": "checkout",
"success_url": "https://partner.example/success",
"cancel_url": "https://partner.example/cancel",
"customer": { "email": "customer@example.com" },
"metadata": { "channel": "mobile_app" }
}
{
"id": "ORD_…",
"object": "order",
"status": "pending_payment",
"partner_reference": "INV-1001",
"currency": "GHS",
"amount": "50.00",
"amount_payable": "50.00",
"product_id": "PRD_…",
"payment": {
"id": "CS_…",
"method": "checkout",
"status": "processing",
"url": "https://omni.mojo-pay.com/pay/CS_…",
"merchant_reference": "FEX-ORD_…-1"
},
"failure": null,
"created_at": "…",
"completed_at": null
}
GET /orders/{id}
Authorization: Bearer <token>
GET /orders
Authorization: Bearer <token>
{
"object": "list",
"data": [
{ "id": "ORD_…", "object": "order", "status": "completed" }
]
}
POST /orders/{id}/cancel
Authorization: Bearer <token>
Configure a webhook URL per API client under Partner Portal → API & webhooks. FEX signs every delivery with FEX-Signature (HMAC-SHA256).
Header format:
FEX-Signature: t=<unix_timestamp>,v1=<hmac_sha256_hex>Signed payload: {timestamp}.{raw_body} using your webhook_secret.
{
"id": "EVT_…",
"type": "order.completed",
"api_version": "2026-06-01",
"created": "2026-08-25T14:30:00+00:00",
"data": {
"object": {
"id": "ORD_…",
"object": "order",
"status": "completed"
}
}
}
| Type | When |
|---|---|
order.pending_payment |
Order created; customer should pay |
order.paid |
Payment confirmed |
order.fulfilling |
Provider fulfillment started |
order.completed |
Terminal success |
order.failed |
Terminal failure |
order.cancelled |
Cancelled by partner or system |
Respond with 2xx quickly. Delivery is at-least-once — dedupe on event id.
Failed responses use the standard envelope. Use error.code for handling and request_id when contacting support. Provider codes (provider_*) can also appear on a failed order as failure.code.
{
"error": {
"code": "validation_failed",
"message": "Product fields failed validation.",
"details": { "errors": { "amount": ["required"] } },
"request_id": "req_…"
}
}
unauthorized
not_found
product_unavailable
validation_failed
quote_unavailable
quote_expired
invalid_state
fx_rate_unavailable
provider_not_found
provider_error