---
url: /how-it-works.md
---
# How it works

Maytes lets customers **pay now or split the cost with friends**. You add a checkout to your online store, the customer pays in the Maytes window, and you capture the payment to finalize the order. Maytes handles the payment and splitting logic.

Every integration starts with your backend **creating a checkout**. The request includes the order's line items, total, and redirect URLs. The customer then pays in the Maytes-hosted window.

The checkout follows an **authorize, then capture** pattern, like a card pre-authorization. Authorization *holds* the customer's funds; capture moves the money.

## One order, two payments

For a split, Maytes runs **two transactions** on the customer's card. This customer is the *lead*:

1. **The lead's own share** — charged when you capture the checkout.
2. **The mates' shares** — held as a second authorization on the lead's card. Mates have **48 hours** to pay Maytes. When the window closes, Maytes captures any unpaid amount from that authorization, so the lead covers mates who did not pay in time.

You do not see or manage the second transaction; it is between Maytes and the customer. **Your full order total is secured when you capture**, whether or not the mates pay. Maytes handles splitting, reminders, and collection.

After paying, the customer stays in Maytes to add their mates, then returns to your site.

## The webhook flow

Maytes sends your backend a signed [`checkout.authorized` webhook](/webhooks) as soon as the payment is authorized. Your webhook handler captures server-to-server while the customer remains in the Maytes window.

The webhook flow validates and captures the order within seconds of payment. The customer **stays in Maytes** to add mates on the web or in the Maytes app, where they can select contacts. If any details are missing, Maytes follows up by SMS. The customer reaches your `return_url` only after this step.

1. The customer chooses Maytes in your online store.
2. Your backend **creates a checkout** with Maytes and gets a `checkout_url`.
3. The customer authenticates and pays in the **Maytes checkout window**. Funds are *authorized* (held), not yet taken.
4. Maytes sends your backend a **`checkout.authorized` webhook**. The customer sees a payment-processing screen while your handler runs.
5. Your handler **captures** the checkout, or cancels it if you cannot fulfill. Capture is synchronous: when the call returns 200, the money has moved.
6. The customer adds the mates who will share the cost, then lands on your `return_url`.

```mermaid
sequenceDiagram
  autonumber
  participant C as Customer
  participant M as Your backend
  participant K as Maytes
  C->>M: Choose "Pay with Maytes"
  M->>K: POST /api/merchant/v1/checkouts
  K-->>M: { checkout_uuid, checkout_url }
  M-->>C: Open checkout_url (Maytes checkout window)
  C->>K: Completes payment → authorized
  K->>M: Webhook: checkout.authorized
  Note over C,K: Customer sees "processing payment…" in the Maytes window
  M->>K: POST /api/merchant/v1/checkouts/{uuid}/capture
  K-->>M: 200 — status: "captured"
  Note over C,K: Customer continues in Maytes (optional split step)
  K-->>C: Redirect to your return_url when done
```

::: warning Fulfill on capture, not on return_url
In the webhook flow, **capture success is your fulfillment trigger**. After capture, the customer may spend several minutes adding mates or close the window without reaching `return_url`. The payment remains valid. Use `return_url` only as a confirmation page, never as proof that the order is paid.
:::

Capture **immediately** from the webhook handler because the customer is waiting on a processing screen. If you cannot fulfill the order, for example because a final stock check fails, call [cancel](/capture-and-status#if-you-can-t-fulfill-the-order) to release the hold. See [Webhooks](/webhooks) for the full handler, signature verification, and delivery semantics.

## Amounts are in minor units

Every API amount is an **integer in the currency's minor unit**. For AUD, `4500` means **AUD 45.00**. Never send decimals. All examples in these docs use AUD.

## Before you begin

[Onboarding](/onboarding) covers setting up your merchant account, credentials, and Stripe payout account. The **[Maytes merchant portal](/portal)** provides:

* **OAuth client credentials** (`client_id` + `client_secret`) — a separate pair for the sandbox and production environments.
* Your **webhook subscription** — endpoint URL, event types, and the signing secret used to verify deliveries.
* Your **merchant account configuration**, connected to your payout account.

Keep your `client_secret` and webhook signing secret on your server — never expose either in browser code.

## Next

* [Quickstart](/quickstart) — a working webhook-flow integration, step by step.
* [Webhooks](/webhooks) — events, signature verification, and delivery semantics.
* [Authentication](/authentication) — getting and using access tokens.
