# Collecting money

Everything here settles through the same Mobile Money rail. What differs is who initiates, where the customer is, and how much you have to build.

## Choosing

| | You need | Customer sees | Reach for it when |
| --- | --- | --- | --- |
| **[Direct charge](/en/payments/overview)** | Their phone number | A USSD prompt, nothing else | You own the checkout and already know who is paying |
| **[Payment link](/en/products/payment-links)** | Nothing but a URL | A hosted page you did not build | You want to sell without writing a checkout |
| **[Invoice](/en/products/invoices)** | A named customer and line items | An itemised bill, by email or WhatsApp | You are billing, not checking out |
| **[Storefront](/en/products/storefronts)** | A catalogue | A shop | You want a catalogue, not a single item |

The short version: **direct charge when you have a checkout, payment link when you do not, invoice when the customer needs a document.**

## How they relate

<Mermaid chart={`
flowchart TD
    subgraph surfaces["What you create"]
        DC["Direct charge<br/>POST /v1/payments"]
        PL["Payment link<br/>POST /v1/payment-links"]
        IN["Invoice<br/>POST /v1/invoices"]
    end
    PL --> HP["Hosted page<br/>checkout_url"]
    IN --> HP
    DC --> RAIL
    HP --> RAIL["Mobile Money collection<br/>MTN / Orange"]
    RAIL --> WH["payment.success<br/>payment.failed"]
`} />

Payment links and invoices are not a different payment system. They are hosted pages in front of the same collection, which is why the [asynchronous model](/en/concepts/how-payments-work), the [failure codes](/en/concepts/errors) and the webhooks are identical across all three. Learn the rail once.

## What they share

**`checkout_url`.** Both links and invoices return it, and it is where you send the customer. Store it rather than rebuilding it from an id — a sandbox URL carries `?type=sandbox`, and dropping the query string produces a page that looks for the resource in live data and 404s.

**The same webhooks.** `payment.success` and `payment.failed` fire for a payment on a link exactly as for a direct charge.

**Idempotency.** Every create call takes an [`Idempotency-Key`](/en/concepts/idempotency).

**Amounts in whole XAF.** Integers, minimum `100`. No minor units, no multiplying by 100. `5000` means five thousand francs.

## One difference that catches people

A payment link created **through the API** carries your API key, so payments on it emit webhooks to your endpoints. A link created **in the dashboard** does not, and you will not receive integrator webhooks for it.

If you are testing webhooks against a link you made by clicking around in the dashboard, that is why nothing is arriving.

## Next steps

- [How a payment works](/en/concepts/how-payments-work) — the rail underneath all four
- [Payment links](/en/products/payment-links) — the no-code surface, and its API
- [Invoices](/en/products/invoices) — itemised billing with a hosted pay page
- [API reference](/en/api/direct-payments) — exact fields for every call
