Skip to content

Payment Intents

A Payment Intent is a central object in the Sangho payment cycle. It represents your intent to collect money from a customer, and orchestrates every step of the process, from attaching a payment method through final confirmation and the creation of a Transaction.

Each payment corresponds to exactly one Payment Intent. Its lifecycle is managed automatically by the Sangho API based on your customer’s actions and the operators’ responses.

Why a Payment Intent instead of a direct payment?

Payment Intents let you handle complex scenarios: 3D Secure authentication, mobile operator redirects, deferred capture, and retrying after a failure — all without ever losing the state of the payment in progress. This is the recommended approach for any robust payment integration.

Lifecycle

requires_payment_methodrequires_confirmationrequires_actionpendingprocessingsucceeded / canceled
StatusMeaningRequired action
requires_payment_methodNo payment method has been attached yet.Present the payment form to the customer.
requires_confirmationA method is attached, awaiting confirmation.Call /confirm/ or pass confirm: true at creation.
requires_actionThe operator requires an additional action (3DS, redirect).Redirect the customer to next_action.redirect_url.
pendingAwaiting a response from the operator (mobile money).Wait for the payment_intent.succeeded webhook.
processingThe payment is being processed by the operator.Do nothing — wait for the webhook.
requires_captureAuthorized — manual capture required (deferred capture).Call /capture/ before it expires.
succeededPayment succeeded. A Transaction has been created.Deliver the service/product.
canceledPermanently canceled. Not recoverable.Create a new Payment Intent if needed.

Endpoints

MéthodeEndpointDescription
POST/payment-intents/Create a Payment Intent
GET/payment-intents/List Payment Intents (paginated, filterable)
GET/payment-intents/{id}/Retrieve a Payment Intent by its ID
PATCH/payment-intents/{id}/Update a Payment Intent (before confirmation)
POST/payment-intents/{id}/confirm/Confirm the payment and trigger processing
POST/payment-intents/{id}/capture/Capture an authorized payment (deferred capture)
POST/payment-intents/{id}/cancel/Permanently cancel

Object schema

ResponsePaymentIntent object
Full structure returned by all GET and POST endpoints of this resource.
json
{
  "id": "pi_3Nx8mLKZ2eZvKYlo28m",
  "object": "payment_intent",
  "reference": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "amount": 15000,
  "amount_capturable": 0,
  "amount_received": 0,
  "currency": "XAF",
  "status": "requires_payment_method",
  "payment_method": null,
  "payment_method_types": ["mobile_money", "bank_card"],
  "customer": "cust_xxxxxxxx",
  "description": "Order #CMD-2026-042",
  "receipt_email": "client@email.com",
  "category": "product",
  "confirm": false,
  "capture_method": "automatic",
  "next_action": null,
  "url": "https://checkout.sangho.ga/pay/pi_xxx",
  "livemode": true,
  "metadata": {
    "order_id": "CMD-2026-042"
  },
  "created_at": "2026-03-01T10:00:00Z",
  "updated_at": "2026-03-01T10:00:00Z"
}

Create a Payment Intent

Instantiates a new Payment Intent with requires_payment_method status. This is the first step of any payment flow with Sangho.

POSTRequest body
amountRequis
integercentsex :15000

Amount to collect, expressed in cents of the currency. For zero-decimal currencies such as XAF/XOF, 1 FCFA = 1 cent (no decimals). For USD/EUR, 1 unit = 100 cents.

The minimum accepted amount is 100 cents (1 XAF). The maximum amount depends on the transaction cap configured on your App. Always use integers — floating-point values are rejected with a 400 error.

currencyRequis
stringISO 4217ex :XAF

ISO 4217 currency code for the payment. Sangho recognizes 132 ISO 4217 currencies, but the currency used must also be enabled on Sangho and included in your planXAF and XOF are available on all plans.

An unknown or disabled currency returns 422 INVALID_CURRENCY. A valid currency that is not included in your plan returns 403 CURRENCY_NOT_IN_PLAN — upgrade to a higher plan to enable it. Once created, the currency field of a Payment Intent can no longer be modified.

payment_method_typesOptionnel
array[string]ex :[“mobile_money”, “bank_card”]

List of payment methods allowed for this Intent. If omitted, all of your App’s active methods are available.

En savoir plus

Possible values: mobile_money, bank_card, paypal. Restricting the types improves the user experience on the payment page and reduces errors related to methods unavailable in a given region.

customerOptionnel
stringCustomer IDex :cust_xxxxxxxx

ID or email of an existing Customer object to associate with this payment. Lets you retrieve a customer’s payment history.

En savoir plus

If you pass an email that isn’t registered yet, Sangho automatically creates a Customer. If you pass an ID and the Customer doesn’t exist, the API returns a 404 error. Associating a Customer also lets you automatically send a receipt if receipt_email is not provided.

descriptionOptionnel
string

Internal description of the payment, not visible to the buyer on the payment page. Useful for finding a payment in your dashboard or via the API.

En savoir plus

Max 500 characters. This description appears in the dashboard’s logs and CSV exports, but not on receipts or the checkout page.

receipt_emailOptionnel
stringemailex :client@email.com

Email address to which Sangho will automatically send the payment receipt after a successful payment.

En savoir plus

If not provided and a Customer is associated, the Customer’s email is used by default. To disable sending a receipt, explicitly pass null.

confirmOptionnel
booleandéfaut :false

If true, attempts to confirm the payment immediately after creation. Requires that payment_method be provided in the same request.

En savoir plus

Useful for server-to-server payments where you already have the payment method. If confirmation fails, the PaymentIntent moves to requires_payment_method — it is not canceled.

payment_methodOptionnel
stringPaymentMethod IDex :meth_xxxxxxxx

ID of an existing payment method to attach immediately to the PaymentIntent.

En savoir plus

Needed if confirm: true. The method must belong to the App or the associated Customer.

categoryOptionnel
stringdéfaut :product

Business category of the payment, used for statistics and OHADA regulatory compliance. Values: product, service, donation, invoice.

capture_methodOptionnel
stringdéfaut :automatic

Determines whether the amount is captured automatically after authorization, or whether you want to capture it manually later.

En savoir plus

automatic: captures immediately after confirmation (standard flow). manual: authorizes only — you must call /capture/ within 7 days, otherwise the authorization is automatically canceled. Manual capture is useful for reservations, pre-orders, or business validations.

metadataOptionnel
object

Key/value dictionary for storing your own data associated with the PaymentIntent — order reference, internal user ID, etc.

En savoir plus

Maximum 50 keys, each key and value being strings of max 500 characters. The metadata is returned in all webhooks related to this PaymentIntent. It is not visible to the end customer.

Create a Payment Intent

bash
curl -X POST https://api.sangho.ga/v1/payment-intents/ \
  -H "Authorization: Bearer sk_prod_xxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: uuid-unique" \
  -d '{
    "amount": 15000,
    "currency": "XAF",
    "payment_method_types": ["mobile_money", "bank_card"],
    "customer": "cust_xxxxxxxx",
    "description": "Order #CMD-2026-042",
    "metadata": { "order_id": "CMD-2026-042" }
  }'
Response201 Created
Status requires_payment_method. The url field contains the checkout URL to redirect your customer to.
json
{
  "id": "pi_3Nx8mLKZ2eZvKYlo28m",
  "object": "payment_intent",
  "amount": 15000,
  "currency": "XAF",
  "status": "requires_payment_method",
  "payment_method_types": ["mobile_money", "bank_card"],
  "customer": "cust_xxxxxxxx",
  "description": "Order #CMD-2026-042",
  "url": "https://checkout.sangho.ga/pay/pi_3Nx8mLKZ",
  "livemode": true,
  "metadata": { "order_id": "CMD-2026-042" },
  "created_at": "2026-03-01T10:00:00Z",
  "updated_at": "2026-03-01T10:00:00Z"
}
Response400 Bad Request
The body contains invalid data. The errors field details each field in error.
Common causes: amount ≤ 0, unsupported currency or currency outside your plan, amount below the App's minimum limit.
json
{
  "status": 422,
  "type": "VALIDATION_ERROR",
  "code": "AMOUNT_TOO_SMALL",
  "message": "The amount is too small. The minimum is 100 XAF.",
  "param": "amount",
  "doc_url": "https://docs.sangho.ga/errors#AMOUNT_TOO_SMALL"
}
Response401 Unauthorized
The API key is missing, expired, or invalid.
Never expose your secret key in frontend code or in a public Git repository.
json
{
  "status": 401,
  "type": "AUTHENTICATION_ERROR",
  "code": "INVALID_API_KEY",
  "message": "Invalid or expired API key.",
  "doc_url": "https://docs.sangho.ga/errors#INVALID_API_KEY"
}

List Payment Intents

Returns a paginated list of all your App’s Payment Intents, sorted by descending creation date by default. Supports filtering, searching, and sorting.

GETQuery parameters
statusOptionnel
stringquery

Filter Payment Intents by status. Accepts the lifecycle values.

En savoir plus

You can pass multiple values separated by a comma: status=succeeded,canceled.

currencyOptionnel
stringISO 4217queryex :XAF

Filter by ISO 4217 currency code.

customerOptionnel
stringquery

Filter by a Customer’s ID or email. Returns all payments associated with that customer.

En savoir plus

You can pass either the ID (cust_xxx) or the exact email address. Email search is case-sensitive.

created_afterOptionnel
stringISO 8601queryex :2026-01-01T00:00:00Z

Returns only Payment Intents created after this date/time (inclusive).

created_beforeOptionnel
stringISO 8601queryex :2026-12-31T23:59:59Z

Returns only Payment Intents created before this date/time (inclusive).

orderingOptionnel
stringquerydéfaut :-created_at

Sort field. Prefix with - for descending order.

En savoir plus

Sortable fields: created_at, amount, status. Examples: ordering=amount (ascending), ordering=-amount (descending).

pageOptionnel
integerquerydéfaut :1

Number of the page to return. Pagination starts at 1.

En savoir plus

If the requested page exceeds the total number of pages, an empty list is returned (not a 404 error).

page_sizeOptionnel
integerquerydéfaut :20

Number of results per page. Minimum: 1. Maximum: 100.

En savoir plus

To retrieve all the Payment Intents for a period, use page_size=100 and iterate while next is non-null in the response.

Pagination

All Sangho list endpoints use page-based pagination (page / page_size). The response is a flat envelope — count, next, previous, and data live at the same level; there is no nested pagination object.

Iterating over all pages

Keep incrementing page as long as next is non-null. This property contains the full URL of the next page, ready to be called directly.

List Payment Intents

bash
# Successful payments in XAF, 50 per page
curl "https://api.sangho.ga/v1/payment-intents/?status=succeeded&currency=XAF&page_size=50" \
  -H "Authorization: Bearer sk_prod_xxxx"
Response200 OK — Paginated list
Flat envelope: count, next, previous, and data live at the same level — no nested pagination object.
json
{
  "count": 142,
  "next": "https://api.sangho.ga/v1/payment-intents/?page=2&page_size=50&status=succeeded",
  "previous": null,
  "data": [
    {
      "id": "pi_3Nx8mLKZ2eZvKYlo28m",
      "object": "payment_intent",
      "amount": 15000,
      "currency": "XAF",
      "status": "succeeded",
      "customer": "cust_xxxxxxxx",
      "created_at": "2026-03-01T10:00:00Z"
    }
  ]
}

Confirm a Payment Intent

Triggers payment processing. Moves the PaymentIntent to processing (or requires_action if an additional step is needed).

POSTConfirmation body (POST)
payment_methodOptionnel
stringPaymentMethod ID

ID of a payment method to attach before confirmation. Required if the PaymentIntent is in requires_payment_method.

Always use an Idempotency-Key

Call /confirm/ with a unique Idempotency-Key header to avoid duplicate confirmations in case of a network timeout. The key must be unique per PaymentIntent.

Capture (deferred capture)

Captures an authorized amount. Available only if capture_method: “manual” and status requires_capture. You can capture an amount lower than the authorized amount.

POSTCapture body (POST)
amount_to_captureOptionnel
integercents

Amount to capture. Must be ≤ amount_capturable. If omitted, captures the full authorized amount.

En savoir plus

Capturing a partial amount automatically cancels the remainder. Example: authorization of 20,000 XAF, capture of 15,000 → 5,000 automatically canceled.

Cancel

Permanently cancels the PaymentIntent. Irreversible. If the PaymentIntent was in requires_capture, the authorization is released with the operator.

Irreversible cancellation

A canceled Payment Intent cannot be reactivated. If you want to retry the payment, you must create a new Payment Intent.

Confirm

bash
curl -X POST https://api.sangho.ga/v1/payment-intents/pi_xxx/confirm/ \
  -H "Authorization: Bearer sk_prod_xxxx" \
  -H "Idempotency-Key: confirm-pi_xxx-1234" \
  -H "Content-Type: application/json" \
  -d '{ "payment_method": "meth_xxxxxxxx" }'
Response200 OK — Confirmed
The status moves to processing or requires_action if an operator redirect is required (next_action non-null).
json
{
  "id": "pi_3Nx8mLKZ2eZvKYlo28m",
  "status": "processing",
  "next_action": null,
  "updated_at": "2026-03-01T10:01:00Z"
}
Response422 — Invalid state
The PaymentIntent is not in a confirmable state (already succeeded, canceled, or processing).
Check the current status before calling /confirm/. A preliminary GET is recommended.
json
{
  "status": 422,
  "type": "VALIDATION_ERROR",
  "code": "PAYMENT_INTENT_NOT_CONFIRMABLE",
  "message": "Cannot confirm a PaymentIntent with status 'succeeded'.",
  "param": "status",
  "doc_url": "https://docs.sangho.ga/errors#PAYMENT_INTENT_NOT_CONFIRMABLE"
}

Partial capture

bash
curl -X POST https://api.sangho.ga/v1/payment-intents/pi_xxx/capture/ \
  -H "Authorization: Bearer sk_prod_xxxx" \
  -H "Content-Type: application/json" \
  -d '{ "amount_to_capture": 12000 }'
Response200 OK — Captured
The payment is captured. amount_received reflects the amount actually collected. Any remaining amount is canceled.
json
{
  "id": "pi_3Nx8mLKZ2eZvKYlo28m",
  "status": "succeeded",
  "amount": 20000,
  "amount_received": 12000,
  "amount_capturable": 0,
  "updated_at": "2026-03-01T10:05:00Z"
}