# Concepts & Domain Entities

Fynex's data model revolves around a small set of domain entities. Understanding these entities and their relationships is the fastest way to make sense of the REST and GraphQL surfaces.

Entities are grouped by concern. For each one you will find: a definition, where it appears in the API (REST endpoint, GraphQL query/mutation, or internal-only), and the key fields a partner needs.

---

## Account & configuration

These entities define who you are in Fynex and how payments are routed.

### SellerAccount

A seller's top-level commercial profile in Fynex. One account owns the API bearer token, one or more wallets, terminals, and split rules.

**API surface:** GraphQL query `sellerAccount(id)` / `sellerAccounts`. Token is rotated via `regenerateSellerAccountToken(merchantId: ID!)`. Not directly accessible via REST — the bearer token implicitly identifies the account on every request.

**Key fields:**
- `authorizationToken` — the bearer token used on all `Authorization: Bearer` REST calls
- `operationalMode` — `demo` or `live`; governs which provider environment receives payments
- `id` (int) — required for GraphQL mutations that target a specific account


---

### Terminal

A processor-bound acceptance point — for example, a specific upstream-processor MID. Each terminal is tied to one `PaymentPartner`, a currency, and a set of allowed instruments. The routing engine selects a terminal for each payment.

**API surface:** GraphQL queries `terminal(id)` / `terminals`. Internal-only for configuration; partners do not reference terminals directly in REST requests.

**Key fields:**
- `paymentPartner` — the upstream PSP this terminal belongs to
- `currencyCode` — currency this terminal accepts
- `paymentMethods` — instrument types (card, google_pay, apple_pay, bank_account)


---

### PaymentPartner

The upstream payment service provider (PSP) routing the request. Partners do not interact with `PaymentPartner` directly; it surfaces in response fields like `providerCode` on payment responses.

**API surface:** GraphQL query (backoffice/internal). The value appears in REST responses as the `providerCode` string — treat its concrete values as platform-managed; check the actual response for the resolved provider.


---

### PaymentConfiguration

The seller-level allowed payment methods, currencies, and rails. Determines what `GET /payment-methods` returns. Configuration is managed by Fynex on your behalf during onboarding.

**API surface:** GraphQL queries `paymentConfiguration(id)` / `paymentConfigurations`. The effective values are surfaced via `GET /payments-api/v1/payment-methods`.

**Key fields:**
- `allowedPaymentMethods` — instrument types enabled for this seller
- `allowedCurrencies` — supported ISO-4217 currency codes
- `allowedPaymentRails` — `card`, `bank_transfer`, `apm`


---

## Money in

These entities represent inbound payment flows.

### GenericPayment

The canonical payment object across all providers. Created by `POST /initialize-payment` (or internally when a hosted checkout session is submitted). Carries the full payment lifecycle, from `pending` to `captured`, `refunded`, `failed` or `cancelled`.

**API surface:** REST — created via `POST /initialize-payment`, acted on by `POST /capture` and `POST /refund`. GraphQL queries `genericPayment(id)` / `genericPayments(...)`.

**Key fields:**
- `externalOrderRef` — your order reference; returned as `paymentId` in REST responses and used as the path parameter for capture/refund
- `lifecycleStatus` — the status to branch on; `status` and the deprecated `legacyStatus` carry the previous values until the switch. See [Payment Lifecycle](https://docs.fynex.ai/payments-api/v2/docs#tag/payment-lifecycle)
- `amount` — in major units via REST responses; stored in minor units internally
- `captureMode` — `auto` or `manual`; accepted, but capture is decided by `autoSettlement` (see [Captures & refunds](https://docs.fynex.ai/payments-api/v2/docs#tag/captures-refunds))
- `requiresAction` / `actionUrl` — set when a 3DS redirect is needed (see [3DS Authentication](https://docs.fynex.ai/payments-api/v2/docs#tag/3ds))
- `failureCode` / `failureDescription` — populated when `lifecycleStatus` is `failed`
- `threeDs` — 3DS authentication result object (version, ECI, CAVV, liability shift)


---

### CheckoutSession

The database row created when you call `POST /checkout` to start a hosted checkout. It is backed by a `pending` `GenericPayment` (previous status value `draft`). The session carries the `sessionId` (UUID) used in all subsequent browser-side checkout routes (`/checkout/{session_id}/*`).

**API surface:** REST — created via `POST /payments-api/v1/checkout`; subsequent browser-side routes (`/checkout/{session_id}/initialize`, `/checkout/{session_id}/finalize`, `/checkout/{session_id}/poll`, `/checkout/{session_id}/events`) are consumed by the hosted page, not directly by partners. Not exposed via GraphQL queries.

**Key fields:**
- `sessionId` — UUID returned on checkout creation; embed in the `checkoutUrl`
- `checkoutUrl` — the URL to redirect the customer to
- `returnUrls.success` / `returnUrls.failure` — where the hosted page redirects after completion

> [!NOTE]
> `CheckoutSession` is internal-only on the GraphQL surface. Use the REST response from `POST /checkout` to obtain the `sessionId` and `checkoutUrl`.

---

### BillingDetails

The customer-side billing identity attached to a payment — name, email, phone, and address. Passed as `billingDetails` in `POST /initialize-payment` and stored on `GenericPayment`.

**API surface:** Nested field in REST request and response bodies; also surfaced as a sub-type in GraphQL `GenericPayment`.

**Key fields:**
- `firstName`, `lastName`, `email`, `phone`
- `addressLine1`, `city`, `postalCode`, `countryCode`
- Aliases accepted on input: `street` = `addressLine1`, `zip` = `postalCode`, `country` = `countryCode`
- `postalCode` (or `zip`) is at most 10 characters after trimming; a longer value is rejected with `400` naming the field that was sent: `billingDetails.postalCode must be at most 10 characters`, or `billingDetails.zip must be at most 10 characters` when only `zip` was sent. Not checked on `paymentType: apm` requests, which never send a postcode


---

### SavedCard

A card stored on Fynex, linked to a `SellerCustomer`, that the Billing API's off-session collection charges against. Created only by the hosted checkout flow when the buyer ticks *save card* and gives an e-mail, on a successful payment with a billing address.

**API surface:** Internal — no public endpoint lists or charges it. There is no "charge saved card by reference" call on this API: the `subscription` block on `/initialize-payment` only flags the processor-side stored-credential relationship and does **not** create a `SavedCard`. Off-session charging happens through Billing invoices — see [Recurring payments](https://docs.fynex.ai/payments-api/v2/docs#tag/recurring).

---

### SellerCustomer

A repeat customer under a specific seller, shared with the Billing API: its `id` is the `sellerCustomerId` that Billing contracts, subscriptions and invoices refer to. Matched by e-mail; carries the seller's own `merchantCustomerId` as a reference and owns the customer's `SavedCard`s.

**API surface:** Created by the hosted checkout flow on the same event as a `SavedCard` — the buyer ticks *save card*, gives an e-mail, and the payment succeeds — or by `POST /billing-api/v1/customers` (resolve-or-create by e-mail). Referenced on `/initialize-payment` via the `merchantCustomerId` field.

**Key fields:**
- `sellerCustomerRef` — the `merchantCustomerId` you passed on `/initialize-payment`
- `sellerAccountId` — the owning seller

---

## Money out

These entities represent outbound payment flows to payees.

### Payout

A wallet-to-payee transfer requested by the seller. Sent via the banking provider. Each payout debits a specific wallet and credits a specific `PayoutMethod`.

**API surface:** REST — `POST /payments-api/v1/payouts` (create), `GET /payouts` (list), `GET /payouts/{id}` (get), `POST /payouts/{id}/cancel`, and `POST /payees/{payee_id}/payouts` to pay a payee directly. GraphQL queries `payout(id)` / `payouts(...)`.

**Key fields:**
- `amount` — decimal string in major units (`"49.99"`), preferred; `amountMinor` (`4999`) is a deprecated fallback that `amount` overrides. Responses carry both.
- `currencyCode`
- `walletId` — source wallet
- `payoutMethodId` — destination bank account
- `description` — the text the beneficiary sees on their bank statement (1–140 SEPA-safe characters); optional today, will become required
- `idempotencyKey` — in the **request body**; the `Idempotency-Key` header is an optional fallback used only when the body field is empty
- `status` — `pending`, `dispatching`, `processing`, `completed`, `failed`, `cancelled`, plus `manual_reconciliation` when an operator has to resolve the row; `approvalStatus` (`awaiting_approval` / `approved` / `rejected` / `compliance_review`) is separate and set when the seller's approval threshold applies — `compliance_review` means the payout is waiting on a screening verdict, not on a human approver


---

### PayoutMethod

A registered bank-account destination for a payee — IBAN, sort code/account number, or other bank-transfer credentials. A payee can have multiple payout methods.

**API surface:** REST — `GET`/`POST /payments-api/v1/payees/{payee_id}/payout-methods`, `PATCH`/`DELETE …/payout-methods/{method_id}`, and the seller's own methods at `/payments-api/v1/payout-methods`. GraphQL queries `payoutMethod(id)` / `payoutMethods(payeeId, ...)` and mutations `createPayoutMethod`, `updatePayoutMethod`, `deletePayoutMethod` remain for dashboard sessions.

**Key fields:**
- `payeeId` — the owning payee
- `currency` — supported currency for this method
- `status` — `active` or `inactive`; only active methods appear in REST listing


---

### Payee

A counterparty under a seller — a sub-merchant, marketplace seller, or any recipient of split funds or payouts. Each payee has a role and can have multiple `PayoutMethod` records.

**API surface:** REST — `GET`/`POST /payments-api/v1/payees`, `GET`/`PATCH`/`DELETE /payees/{payee_id}`, and `POST /payees/setup` to create a payee, payout method and wallet in one call. GraphQL queries `payee(id)` / `payees` and mutations `createPayee`, `updatePayee`, `deletePayee` remain for dashboard sessions.

**Key fields:**
- `displayName` — human-readable label
- `role` — `Itself` (the seller itself), `Contractor`, `Tax`, or `fynex_platform`
- `status` — `Active` or `Disabled`


---

### VirtualAccount

A customer pay-in IBAN issued via the virtual-account provider. Customers can be given a dedicated IBAN to send funds directly into the seller's account without a card payment.

**API surface:** GraphQL queries `virtualAccount(id)` / `virtualAccounts(first, after, type)`.

**Key fields:**
- `iban` — the virtual IBAN assigned to this account
- `currency` — account currency
- `type` — virtual account type


---

## Balances

These entities represent the seller's internal ledger.

### Wallet

A per-seller, per-currency balance ledger. Settlement of card payments credits the relevant wallet. Payouts debit from it.

**API surface:** REST — `GET`/`POST /payments-api/v1/wallets`, `GET /wallets/{wallet_id}`, `GET /wallets/{wallet_id}/transactions`, `POST /wallets/{wallet_id}/fund`. GraphQL queries `wallet(id)` / `wallets(...)` and mutations `createWallet`, `updateWallet` remain for dashboard sessions.

**Key fields:**
- `currencyCode` — one wallet per currency
- `balance` — current available balance
- `sellerAccountId`

**Wallet balance, credit balance and customer balance.** A *wallet balance*
is money a seller owns and is paid out from (`wallets`). A *credit balance*
is stored value a buyer holds and spends instead of cash; it lives in the
credit ledger, anchored either on a billing contract (the merchant's
customer) or on a platform consumer (the coupon wallet). A *customer balance*
is that credit balance for one consumer. The two stored-value systems never
hold the same money: credit becomes wallet money only when an order it funded
settles to the seller.


---

### WalletEntry

An append-only ledger entry on a wallet — every credit or debit is recorded as an immutable entry. Used for reconciliation.

**API surface:** GraphQL (nested within `Wallet`).

**Key fields:**
- `amount` — signed; positive = credit, negative = debit
- `type` — entry type (settlement, payout, fee, etc.)
- `referenceId` — links back to the originating `GenericPayment` or `Payout`


---

### WalletTransfer

An inter-wallet movement — for example, when a split execution moves funds from the seller wallet to a payee wallet.

**API surface:** GraphQL (nested within `Wallet`).

**Key fields:**
- `fromWalletId` / `toWalletId`
- `amount`
- `referenceType` — indicates the source (split execution, manual transfer, etc.)


---

## Splits

These entities distribute payment proceeds across multiple payees. What a split does with the money — rounding, fees, over-allocation, the remainder, holds, refunds and chargebacks — is described in one place: [Split Rules](https://docs.fynex.ai/payments-api/v2/docs#tag/splits), section *How Fynex splits money*.

### SplitRule

A per-seller rule that distributes a settled payment's proceeds across one or more payees. Each rule has one or more `SplitRuleLine` entries.

**API surface:** REST — `GET`/`POST /payments-api/v1/split-rules`, `GET /split-rules/active`, `POST /split-rules/calculate` (see **Splits**). GraphQL queries `splitRule(id)` / `splitRules(...)` and mutations `createSplitRule`, `updateSplitRule`, `deleteSplitRule` remain for dashboard sessions.

**Key fields:**
- `name` — descriptive name for this rule
- `sellerAccountId`
- `lines` — list of `SplitRuleLine`


---

### SplitRuleLine

One line within a `SplitRule` — specifies a payee and their share (by amount or percentage).

**API surface:** Nested within `SplitRule` in GraphQL.

**Key fields:**
- `payeeId` — recipient
- `amount` or `percentage` — the payee's share
- `currencyCode`


---

### SplitExecution

A historical record of a split rule being applied to a specific settled payment. Created automatically when a payment's `settlementStatus` reaches `deposit_confirmed` and a matching split rule exists.

**API surface:** REST — `GET /payments-api/v1/payments/{payment_id}/split` and `GET /payments/{paymentId}/split-decisions`. GraphQL query `splitExecutions(dateFrom, dateTo, sellerAccountId)` remains for dashboard sessions.

**Key fields:**
- `splitRuleId` — the rule that was applied
- `genericPaymentId` — the payment that triggered the execution
- `executedAt`
- `lines` — actual amounts distributed per payee


## See also

- **[Quickstart](https://docs.fynex.ai/payments-api/v2/docs#tag/quickstart)** — Take your first payment in 5 minutes.
- **[Payment Lifecycle](https://docs.fynex.ai/payments-api/v2/docs#tag/payment-lifecycle)** — All GenericPayment and Payout statuses and transitions.
- **[Payouts](https://docs.fynex.ai/payments-api/v2/docs#tag/payouts)** — Create and track wallet-to-payee payouts.
- **[Hosted Checkout](https://docs.fynex.ai/payments-api/v2/docs#tag/hosted-checkout)** — Use the hosted checkout page to accept payments without handling card data.
