# 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]
> All examples target the **staging** environment — no real cards, no real money. Switch the base URL to `https://api.fynex.ai/payments-api/v1` when you are ready for production.

- **API base URL:** `https://staging-api.fynex.ai/payments-api/v1`
- **Full API reference:** this site
- **Dashboard:** `https://staging-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://staging-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 a plain string — there is no `sk_test_`-style 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.

If you don't have dashboard access yet, ask your Fynex contact to set you up. Store the token and base URL in your environment:

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

See [Authentication](https://api.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://staging-api.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://api.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://api.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 — Demo accounts exist on both `https://staging-api.fynex.ai` and
`https://api.fynex.ai`. Use any of these Visa sandbox numbers:

| Card number | Notes |
|-------------|-------|
| `4111 1111 1111 1111` | Universal Visa test card |
| `4530 9100 0001 2345` | Visa |
| `4037 1122 3300 0001` | Visa |

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]
> 3DS is controlled by the `skip3DS` request flag, **not** by the card number. Don't expect a particular card number to force "approved" vs "declined" — that's controlled by the flow and the sandbox challenge page.

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://api.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 the Fynex `status` (e.g. `provider_completed`, `settled`, `failed`, `cancelled`) along with `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://api.fynex.ai/payments-api/v2/docs#tag/polling-sse) for the full verification pattern.

## Conventions to know

- **`Idempotency-Key` header is mandatory** on every `POST` (checkout, initialize-payment, finalize-payment, refund). Use a fresh UUID per logical request; retrying with the *same* key safely returns the existing operation instead of creating a duplicate.
- **`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 `initialize-payment`** (and recommended on `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://api.fynex.ai/payments-api/v2/docs#tag/captures-refunds)** — manual capture (`autoSettlement: false`) and refunding settled payments.
- **[Server-to-server](https://api.fynex.ai/payments-api/v2/docs#tag/server-to-server)** — the full direct-integration and 3DS redirect lifecycle.
- **[Polling & SSE](https://api.fynex.ai/payments-api/v2/docs#tag/polling-sse)** — verify payment status without webhooks.

## 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` before sending a test PAN; see [Test cards & sandbox](https://api.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.
