# Getting started

This guide takes you from zero to your first successful **test payment** on the Fynex sandbox. It is the broad "first steps" tour: get a token, verify it, choose an integration style, use sandbox cards, confirm the outcome, and learn the conventions you'll rely on everywhere else.

> [!NOTE]
> Examples use this environment's API, `https://api.fynex.ai`. Whether a payment is a test or real is decided by your **account**, not the host: a **Demo** account never moves real money. See [Going live](https://docs.fynex.ai/payments-api/v2/docs#tag/going-live) when you are ready for real payments.

- **API base URL:** `https://api.fynex.ai/payments-api/v1`
- **Full API reference:** this site
- **Dashboard:** `https://dashboard.fynex.ai`

## 1. Get your API token

Every request is authenticated with a **seller bearer token**, which you obtain yourself from the dashboard:

1. Log in to `https://dashboard.fynex.ai` with your username and password.
2. Select your seller account.
3. Open the **Integration** page.
4. Click the reveal (eye) icon to show the token, then **Copy**.

The token is an opaque string with no prefix — it is exactly the value you
pass as `Authorization: Bearer <token>`. Treat it like a password.

> [!CAUTION]
> The **Regenerate** button on the Integration page issues a *new* token and **immediately invalidates the old one** — there is no overlap window. Only use it when you intend to rotate. For first-time setup, just reveal and copy.

Store the token and base URL in your environment:

```bash
export FYNEX_API="https://api.fynex.ai/payments-api/v1"
export FYNEX_TOKEN="<the token you copied>"
```

See [Authentication](https://docs.fynex.ai/payments-api/v2/docs#tag/authentication) for token storage, rotation, and error details.

## 2. Verify the token works

The quickest "is my token alive?" check returns the payment methods enabled on your account:

```bash
curl -sS "$FYNEX_API/payment-methods" \
  -H "Authorization: Bearer $FYNEX_TOKEN"
```

- **`200 OK`** with a JSON body → your token works and your account is active.
- **`401 Unauthorized`** → the token is missing, malformed, or invalid.
- **`403 seller account is not active`** → the token is **valid and recognised**, but the account isn't active. New **demo** accounts are activated automatically, so you normally won't see this in the sandbox; if you do, contact Fynex with your seller account ID. (Going **live** for real-money payments requires KYB + a Fynex-assigned live terminal.)

## 3. Take your first test payment

There are two integration styles. Start with **hosted checkout** — it's the fastest and keeps your servers out of PCI scope.

### Option A — Hosted checkout (recommended first)

Fynex hosts the card form; you create a session and redirect the customer to it.

```bash
curl -sS -X POST "$FYNEX_API/checkout" \
  -H "Authorization: Bearer $FYNEX_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "externalOrderRef": "ORDER-DEMO-1",
    "amount": 19.99,
    "currencyCode": "GBP",
    "countryCode": "GB",
    "autoSettlement": true,
    "returnUrls": {
      "success": "https://example.com/success",
      "failure": "https://example.com/failure"
    }
  }'
```

A `201 Created` response returns a `checkoutUrl`:

```json
{
  "sessionId": "6f9b84e1-3b83-4fb9-9f42-a8ac27d11d6b",
  "checkoutUrl": "https://pay.fynex.ai/checkout/6f9b84e1-...",
  "expiresAt": "2026-04-29T11:30:00Z"
}
```

Open `checkoutUrl` in a browser and pay with a sandbox card (see step 4). The page redirects to your `returnUrls.success` or `returnUrls.failure` when done. For the full field-by-field hosted-checkout walkthrough, see the [Quickstart](https://docs.fynex.ai/payments-api/v2/docs#tag/quickstart).

### Option B — Server-to-server

Submit card details directly to the API. Use this when you collect card data yourself.

```bash
curl -sS -X POST "$FYNEX_API/initialize-payment" \
  -H "Authorization: Bearer $FYNEX_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "externalOrderRef": "TEST-HAPPY-1",
    "amount": 19.99,
    "paymentType": "card",
    "paymentMethod": "card",
    "currencyCode": "GBP",
    "countryCode": "GB",
    "autoSettlement": true,
    "skip3DS": true,
    "cardData": {
      "cardNumber": "4111111111111111",
      "expMonth": 12,
      "expYear": 2028,
      "holderName": "Test User",
      "cvv": "123"
    },
    "returnLinks": [
      { "rel": "default", "href": "https://example.com/return", "method": "GET" }
    ]
  }'
```

With `"skip3DS": true` the response has `requiresAction: false` and the payment proceeds straight through. To test the 3DS flow, omit `skip3DS` (or set it `false`) — the response then returns `requiresAction: true` and an `actionUrl`; redirect the customer there, let them complete the challenge, then call `POST /finalize-payment` with the same `paymentId`. See [Server-to-server](https://docs.fynex.ai/payments-api/v2/docs#tag/server-to-server) for the full lifecycle.

## 4. Sandbox test cards

Test cards work on a **Demo** account. What decides it is the account's operational mode,
never the host — a Demo account is a sandbox account on any Fynex host. For a guaranteed
success on **either** option above, use:

| Card number | Notes |
|-------------|-------|
| `4000 0000 0000 2701` | Visa — authenticates frictionlessly, reaches `lifecycleStatus` `captured` |

For all of them:

- **Expiry month:** any future month (e.g. `12`)
- **Expiry year:** any future year — 4-digit (`2028`) recommended
- **CVV:** any 3 digits (e.g. `123`)
- **Cardholder name:** Latin letters (`A-Z`), spaces, apostrophes, dots, or hyphens only

> [!NOTE]
> On **Option B** (server-to-server) with `skip3DS: true`, 3DS never runs and any well-formed
> card number reaches the same generic success/decline path. On **Option A** (hosted checkout)
> and on Option B with `skip3DS` omitted or `false`, 3DS always runs and the card's PAN decides
> the outcome — see [Test cards & sandbox](https://docs.fynex.ai/payments-api/v2/docs#tag/test-cards) for the full decline and 3DS-challenge
> card set.

You can use any well-formed billing data (e.g. `test@example.com`, `Test User`, `+44 7700 900000`) — the sandbox doesn't validate it against real services, and no emails are sent. See [Test cards](https://docs.fynex.ai/payments-api/v2/docs#tag/test-cards) for the full reference.

## 5. Check the result

You have two ways to confirm a payment's outcome:

1. **Poll** the payment status (same token):

   ```bash
   curl -sS "$FYNEX_API/payments/TEST-HAPPY-1" \
     -H "Authorization: Bearer $FYNEX_TOKEN"
   ```

   The response includes `lifecycleStatus` (e.g. `captured`, `failed`, `cancelled` — see [Payment Lifecycle](https://docs.fynex.ai/payments-api/v2/docs#tag/payment-lifecycle)) along with `status`, `amount`, `currencyCode`, `countryCode`, `paymentType`, `paymentMethod`, `externalOrderRef`, the `failureCode` / `failureDescription` / `failureStage` if the payment failed, and the `createdAt` / `updatedAt` / `failedAt` timestamps.

2. **Webhooks** — Fynex sends a `PaymentCompleted` webhook to the URL(s) configured on your account. **Your endpoint must return HTTP `200`**; any other status is retried (up to 3 times) and then marked failed.

> [!NOTE]
> Distinguish `cancelled` (customer abandoned the form) from `failed` (hard decline) — show a neutral "payment not completed" message for `cancelled`, not an error.

See [Polling & SSE](https://docs.fynex.ai/payments-api/v2/docs#tag/polling-sse) for the full verification pattern.

## Conventions to know

- **`Idempotency-Key` header is mandatory on the payment operations** — checkout, initialize-payment, finalize-payment, capture, refund and refund cancellation. Use a fresh UUID per logical request; retrying with the *same* key safely returns the existing operation instead of creating a duplicate. Payouts take `idempotencyKey` in the body. Creating a payee, a payee setup, a payout method, a webhook or a split rule accepts the header optionally; wallet routes do not read it.
- **`returnLinks` vs `returnUrls`:** server-to-server uses `returnLinks` (an array; each item has `rel` ∈ `default | on_completed | on_failed | on_cancelled`, an `href`, and `method: "GET"`). Hosted checkout uses `returnUrls` at session creation.
- **`countryCode` is required on both `initialize-payment` and `checkout`**; if your account/terminal is pinned to a country, it must match it.
- **Amounts** are in major units (e.g. `19.99` = £19.99).

## Common next steps

- **[Captures & refunds](https://docs.fynex.ai/payments-api/v2/docs#tag/captures-refunds)** — manual capture (`autoSettlement: false`) and refunding captured payments.
- **[Server-to-server](https://docs.fynex.ai/payments-api/v2/docs#tag/server-to-server)** — the full direct-integration and 3DS redirect lifecycle.
- **[Polling & SSE](https://docs.fynex.ai/payments-api/v2/docs#tag/polling-sse)** — verify payment status without webhooks.

## Connect an AI agent (MCP)

An MCP endpoint for AI agents is in preview and not yet available on production.

## Going to production

When you're ready, use your **Live** account's token — get it from the production dashboard's (`https://dashboard.fynex.ai`) Integration page, the same way as staging. Tokens are per-environment and independent.

**Never send test card numbers on a Live account.** Note the wording: sandbox versus real card networks is a property of your account's **operational mode**, not of the host you call — Demo accounts exist on both environments, and test cards are correct on any of them. Confirm `operationalMode` with `GET /account` before sending a test PAN; see [Test cards & sandbox](https://docs.fynex.ai/payments-api/v2/docs#tag/test-cards).

## Need help?

Reach out to your Fynex contact with your `externalOrderRef` and the approximate time of the request, and we can trace it end to end.
