{
  "openapi": "3.0.1",
  "info": {
    "title": "Omno Cashier API",
    "description": "Cashier API operations, on `/v3/public/...`. Single source of truth; the canonical reference for every operation is under Other APIs.",
    "version": "3.0.0"
  },
  "servers": [
    {
      "url": "https://api.omno.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Cashier",
      "description": "Create a Cashier session and verify the resulting transactions."
    }
  ],
  "paths": {
    "/v3/public/cashier/session": {
      "post": {
        "tags": [
          "Cashier Session"
        ],
        "summary": "Create cashier session",
        "description": "Creates a cashier session for a customer and returns the `sessionId`, the hosted URLs, and a short-lived `token` used to open the session. Open the session on your frontend with the [Web SDK](https://docs.omno.com/cashier/sdk/quick-start), forwarding both `sessionId` and `token`; see the Guides topic [Integrating the Cashier](https://docs.omno.com/cashier/integrate) for how the backend call and the frontend fit together.\n\n> ℹ️ Treat `token` like a credential: pass it from your backend to the > frontend only to open this session, and never log it. Omno verifies it > against its published signing keys (JWKS) — you do not validate it > yourself.\n\n### Selecting payment types\n`paymentTypes` controls which methods appear in the cashier. Allowed values: `CARD`, `APM`, `CRYPTO`. Provide one value or any combination.\n\n> ⚠️ Only the listed types are shown. To accept card payments you **must** include `CARD`; a method you omit is not available to the customer.\n\nExamples: `[\"CARD\"]` (card only — also used for a Single Payment card session and for Hosted Payment Fields), `[\"APM\"]` (APM only), `[\"CARD\",\"CRYPTO\"]`, `[\"CARD\",\"APM\",\"CRYPTO\"]`. The JSON key is `paymentTypes`.\n\n### Deposit-only / withdrawal-only\nSet `disallowWithdrawal: true` for a deposit-only session, or `disallowDeposit: true` for a withdrawal-only session. `balance` is shown on the withdrawal widget. Don't set both `disallowDeposit` and `disallowWithdrawal` to `true`.\n\n### Customer identification\nIdentify the customer with exactly one of: an inline `customer` object, an `externalCustomerId`, or an `internalCustomerId` (Omno customer ID). Send exactly one.\n\n### Session lifetime\nThe session — and its `token` — is valid for **15 minutes from creation**. The token can be reused for the same session until it expires. Create the session right before you open the Cashier, not at page load.\n",
        "operationId": "createCashierSession",
        "requestBody": {
          "description": "Create Cashier Request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCashierSessionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Cashier session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateCashierSessionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v3/public/customer": {
      "post": {
        "tags": [
          "Customer"
        ],
        "summary": "Create or update customer",
        "description": "Creates or updates a customer for the authenticated merchant. Calling again with the same `externalUserId` updates the existing customer. `customerGroups` and `kyc.kycLevels` drive PSP eligibility — see [Routing & PSP Eligibility](https://docs.omno.com/guides/concepts/routing).",
        "operationId": "createOrUpdateCustomer",
        "requestBody": {
          "description": "Create customer request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Customer created or updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v3/public/payin/{payinId}": {
      "get": {
        "tags": [
          "Get Transaction Info"
        ],
        "summary": "Fetch payin transaction",
        "description": "Returns the pay-in transaction for the given ID. This is the authoritative status check for a pay-in, used alongside webhooks. Never rely on redirects or client-side events for the final status.",
        "operationId": "fetchPayInTransaction",
        "parameters": [
          {
            "name": "payinId",
            "in": "path",
            "description": "Payment transaction ID",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "944732c4608c441aa91379478b91f76e"
          }
        ],
        "responses": {
          "200": {
            "description": "Payment transaction details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayInTransaction"
                },
                "examples": {
                  "success": {
                    "summary": "Successful card pay-in",
                    "value": {
                      "id": "944732c4608c441aa91379478b91f76e",
                      "amount": 100,
                      "merchantId": "944732c4608c441aa91379478b91f76e",
                      "customerId": "944732c4608c441aa91379478b91f76e",
                      "orderId": "order-2026-000201",
                      "currency": "EUR",
                      "status": "SUCCESS",
                      "initialAmount": 100,
                      "initialCurrency": "EUR",
                      "cardMask": "1234 56** **** 1234",
                      "cardBrand": "VISA",
                      "merchantPspId": "944732c4-608c-441a-a913-79478b91f76e",
                      "pspTransactionId": "944732c4-608c-441a-a913-79478b91f76e",
                      "transactionType": "CARD",
                      "createdAt": "2026-09-25T10:00:00Z",
                      "updatedAt": "2026-09-25T10:00:05Z"
                    }
                  },
                  "declined": {
                    "summary": "Declined card pay-in",
                    "value": {
                      "id": "944732c4608c441aa91379478b91f76e",
                      "amount": 100,
                      "merchantId": "944732c4608c441aa91379478b91f76e",
                      "customerId": "944732c4608c441aa91379478b91f76e",
                      "orderId": "order-2026-000202",
                      "currency": "EUR",
                      "status": "DECLINED",
                      "initialAmount": 100,
                      "initialCurrency": "EUR",
                      "cardMask": "1234 56** **** 1234",
                      "cardBrand": "VISA",
                      "merchantPspId": "944732c4-608c-441a-a913-79478b91f76e",
                      "pspTransactionId": "944732c4-608c-441a-a913-79478b91f76e",
                      "transactionType": "CARD",
                      "statusReason": {
                        "reason": "Insufficient funds",
                        "detailedStatus": "INSUFFICIENT_FUNDS",
                        "status": "DECLINED"
                      },
                      "createdAt": "2026-09-25T10:00:00Z",
                      "updatedAt": "2026-09-25T10:00:04Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v3/public/payout/{payoutId}": {
      "get": {
        "tags": [
          "Get Transaction Info"
        ],
        "summary": "Fetch payout transaction",
        "description": "Returns the payout transaction for the given ID. This is the authoritative status check for a payout, used alongside webhooks. Never rely on redirects or client-side events for the final status.",
        "operationId": "fetchPayoutTransaction",
        "parameters": [
          {
            "name": "payoutId",
            "in": "path",
            "description": "Payout ID. Returned by `createPayout`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "944732c4608c441aa91379478b91f76e"
          }
        ],
        "responses": {
          "200": {
            "description": "Payout transaction",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutTransaction"
                },
                "examples": {
                  "processed": {
                    "summary": "Processed payout",
                    "value": {
                      "id": "944732c4608c441aa91379478b91f76e",
                      "amount": 100,
                      "merchantId": "944732c4608c441aa91379478b91f76e",
                      "customerId": "944732c4608c441aa91379478b91f76e",
                      "orderId": "order-2026-000123",
                      "currency": "EUR",
                      "status": "PROCESSED",
                      "initialAmount": 100,
                      "initialCurrency": "EUR",
                      "processorPspId": "944732c4608c441aa91379478b91f76e",
                      "pspTransactionId": "944732c4-608c-441a-a913-79478b91f76e",
                      "transactionType": "BANK",
                      "createdAt": "2026-09-25T10:00:00Z",
                      "updatedAt": "2026-09-25T10:00:08Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v3/public/payout/{payoutId}/confirm": {
      "put": {
        "tags": [
          "Confirm / Reject Payout"
        ],
        "summary": "Confirm payout transaction",
        "description": "Confirms a payout that is in `WAITING_FOR_CONFIRMATION`. After confirmation the transaction starts processing and its status becomes `PENDING`. Used when a payout requires manual approval, across Cashier, Direct Link and Payment Page flows.",
        "operationId": "confirmPayout",
        "parameters": [
          {
            "name": "payoutId",
            "in": "path",
            "description": "Payout ID. Returned by `createPayout`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "944732c4608c441aa91379478b91f76e"
          }
        ],
        "responses": {
          "204": {
            "description": "Payout transaction confirmed. Status becomes `PENDING`."
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict. The payout is not in `WAITING_FOR_CONFIRMATION` and cannot be confirmed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v3/public/payout/{payoutId}/reject": {
      "put": {
        "tags": [
          "Confirm / Reject Payout"
        ],
        "summary": "Reject payout transaction",
        "description": "Rejects a payout that is in `WAITING_FOR_CONFIRMATION`. After rejection the transaction is **not** sent to a PSP and its status becomes `REJECTED`. Used when a payout requires manual approval, across Cashier, Direct Link and Payment Page flows.",
        "operationId": "rejectPayout",
        "parameters": [
          {
            "name": "payoutId",
            "in": "path",
            "description": "Payout ID. Returned by `createPayout`.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "944732c4608c441aa91379478b91f76e"
          }
        ],
        "responses": {
          "204": {
            "description": "Payout transaction rejected. Status becomes `REJECTED`."
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict. The payout is not in `WAITING_FOR_CONFIRMATION` and cannot be rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "schemas": {
      "CustomerBilling": {
        "required": [
          "address",
          "city",
          "countryCode",
          "postalCode",
          "state"
        ],
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "Customer billing address.",
            "example": "123 Main St"
          },
          "city": {
            "type": "string",
            "description": "Customer billing city.",
            "example": "Atlanta"
          },
          "state": {
            "type": "string",
            "description": "Customer billing state.",
            "example": "GA"
          },
          "countryCode": {
            "type": "string",
            "description": "Customer billing country code (ISO 3166-1 alpha-2).",
            "example": "US"
          },
          "postalCode": {
            "type": "string",
            "description": "Customer billing postal code.",
            "example": "30308"
          }
        },
        "description": "Customer billing information"
      },
      "CustomerKyc": {
        "type": "object",
        "properties": {
          "idType": {
            "type": "string",
            "description": "Identity document type.",
            "example": "passport"
          },
          "idNumber": {
            "type": "string",
            "description": "Identity document number.",
            "example": "A12345678"
          },
          "idCountry": {
            "type": "string",
            "description": "Country that issued the identity document (ISO 3166-1 alpha-2).",
            "example": "US"
          },
          "idExpirationDate": {
            "type": "string",
            "format": "date",
            "description": "Identity document expiration date.",
            "example": "2030-12-31"
          },
          "nationality": {
            "type": "string",
            "description": "Customer nationality (ISO 3166-1 alpha-2).",
            "example": "US"
          },
          "countryOfBirth": {
            "type": "string",
            "description": "Customer country of birth (ISO 3166-1 alpha-2).",
            "example": "US"
          },
          "kycLevels": {
            "type": "array",
            "description": "KYC levels associated with the customer. Merchant-defined string labels, matched against each provider's KYC rules during eligibility filtering.",
            "items": {
              "type": "string"
            },
            "example": [
              "Identity Check",
              "Mail Verification"
            ]
          },
          "allowBypass": {
            "type": "boolean",
            "description": "Whether KYC requirements may be bypassed for this customer.",
            "example": true
          }
        },
        "description": "Customer KYC information"
      },
      "CustomerRequest": {
        "required": [
          "billing",
          "dateOfBirth",
          "email",
          "externalUserId",
          "firstName",
          "lastName",
          "phoneNumber"
        ],
        "type": "object",
        "properties": {
          "externalUserId": {
            "type": "string",
            "description": "Your unique identifier for this customer. Calling the customer endpoint again with the same value updates the existing customer.",
            "example": "3183818381183"
          },
          "firstName": {
            "type": "string",
            "description": "Customer first name.",
            "example": "John"
          },
          "lastName": {
            "type": "string",
            "description": "Customer last name.",
            "example": "Doe"
          },
          "email": {
            "type": "string",
            "description": "Customer email.",
            "example": "john.doe@example.com"
          },
          "phoneNumber": {
            "type": "string",
            "description": "Customer phone number.",
            "example": "1 1234567890"
          },
          "dateOfBirth": {
            "type": "string",
            "description": "Customer date of birth.",
            "format": "date",
            "example": "1990-12-01"
          },
          "userName": {
            "type": "string",
            "description": "Customer username.",
            "example": "John123"
          },
          "customerGroups": {
            "type": "array",
            "description": "Customer groups the customer belongs to. Merchant-defined string labels, matched against each provider's group rules during eligibility filtering.",
            "items": {
              "type": "string"
            },
            "example": [
              "Vipgroup"
            ]
          },
          "billing": {
            "$ref": "#/components/schemas/CustomerBilling"
          },
          "kyc": {
            "$ref": "#/components/schemas/CustomerKyc"
          }
        },
        "description": "Customer information"
      },
      "CreateCashierSessionRequest": {
        "required": [
          "currency"
        ],
        "type": "object",
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/CustomerRequest"
          },
          "externalCustomerId": {
            "type": "string",
            "description": "Existing merchant-side customer identifier. Optional alternative to an inline `customer` object."
          },
          "internalCustomerId": {
            "type": "string",
            "description": "Existing Omno customer ID. Optional alternative to an inline `customer` object."
          },
          "currency": {
            "type": "string",
            "description": "Currency for the cashier session, in which all pay-in/pay-out transactions are created (ISO 4217).",
            "example": "EUR"
          },
          "amount": {
            "type": "string",
            "description": "Pre-fills the deposit amount for the session.",
            "example": "1000.50"
          },
          "balance": {
            "type": "string",
            "description": "Current balance of the customer. Shown on the withdrawal widget.",
            "example": "1000.50"
          },
          "kycVerified": {
            "type": "boolean",
            "description": "Whether this customer is KYC verified in your system.",
            "example": true
          },
          "previousTransactionCount": {
            "type": "integer",
            "description": "Number of previous transactions the customer made in your system.",
            "minimum": 0,
            "example": 5
          },
          "paymentTypes": {
            "type": "array",
            "description": "Payment methods shown in the cashier. Provide one value or any combination. Only the listed types are shown; to accept card payments you must include `CARD`. Provide a single value (for example `[\"CARD\"]`) for a Single Payment or Hosted Payment Fields session.",
            "minItems": 1,
            "items": {
              "type": "string",
              "enum": [
                "CARD",
                "APM",
                "CRYPTO"
              ]
            },
            "example": [
              "CARD",
              "APM",
              "CRYPTO"
            ]
          },
          "disallowDeposit": {
            "type": "boolean",
            "description": "When `true`, deposits are not offered in the session (withdrawal-only session). Don't set both `disallowDeposit` and `disallowWithdrawal` to `true`.",
            "example": false
          },
          "disallowWithdrawal": {
            "type": "boolean",
            "description": "When `true`, withdrawals are not offered in the session (deposit-only session). Don't set both `disallowDeposit` and `disallowWithdrawal` to `true`.",
            "example": false
          },
          "merchantTransactionId": {
            "type": "string",
            "description": "Merchant's external transaction reference."
          }
        }
      },
      "CreateCashierSessionResponse": {
        "required": [
          "sessionId"
        ],
        "type": "object",
        "properties": {
          "sessionId": {
            "type": "string",
            "format": "uuid",
            "description": "Cashier session ID. Pass this to the Web SDK `open({ sessionId, token })`.",
            "example": "25aee2fd-fd2a-4a1c-a127-df26206b2a30"
          },
          "token": {
            "type": "string",
            "format": "jwt",
            "description": "JWT that authorizes opening this Cashier session and nothing else. Required: pass it with `sessionId` to `open()` in the Web SDK (or as the `omCashierToken` query parameter — `ct` is an accepted alias — on hosted URLs). Valid for the session's lifetime — 15 minutes from creation. It authorizes only this one session. Treat it as a credential: never log or store it. You don't need to decode or validate it.",
            "example": "eyJhbGciOiJSUzI1NiIsImtpZCI6Imtf..."
          },
          "checkoutUrl": {
            "type": "string",
            "format": "url",
            "description": "Hosted cashier URL (both deposit and withdrawal).",
            "example": "https://checkout.omno.com/payments/cashier/25aee2fd-fd2a-4a1c-a127-df26206b2a30"
          },
          "depositUrl": {
            "type": "string",
            "format": "url",
            "description": "Hosted cashier URL that lands directly on deposit.",
            "example": "https://checkout.omno.com/payments/cashier/25aee2fd-fd2a-4a1c-a127-df26206b2a30/deposit"
          },
          "withdrawalUrl": {
            "type": "string",
            "format": "url",
            "description": "Hosted cashier URL that lands directly on withdrawal.",
            "example": "https://checkout.omno.com/payments/cashier/25aee2fd-fd2a-4a1c-a127-df26206b2a30/withdraw"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Standard error envelope. `VALIDATION_ERROR` (on `400`) is the confirmed key. The full `errorKey` catalogue and error mapping are provided and handled by the Omno integration team during integration.",
        "properties": {
          "errorKey": {
            "type": "string",
            "description": "Machine-readable error identifier.",
            "example": "VALIDATION_ERROR"
          },
          "errorMessage": {
            "type": "string",
            "description": "Human-readable error description.",
            "example": "currency must not be null"
          },
          "errorCode": {
            "type": "integer",
            "format": "int32",
            "description": "HTTP status code associated with the error.",
            "example": 400
          }
        }
      },
      "CustomerResponse": {
        "required": [
          "dateOfBirth",
          "email",
          "externalUserId",
          "firstName",
          "id",
          "lastName",
          "merchantId",
          "phoneNumber"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Omno customer ID.",
            "example": "123456789"
          },
          "firstName": {
            "type": "string",
            "description": "Customer first name.",
            "example": "John"
          },
          "lastName": {
            "type": "string",
            "description": "Customer last name.",
            "example": "Doe"
          },
          "externalUserId": {
            "type": "string",
            "description": "Merchant-specified customer external user ID.",
            "example": "3183818381183"
          },
          "merchantId": {
            "type": "string",
            "description": "Merchant ID associated with the customer.",
            "example": "123456789"
          },
          "email": {
            "type": "string",
            "description": "Customer email.",
            "example": "john.doe@example.com"
          },
          "phoneNumber": {
            "type": "string",
            "description": "Customer phone number.",
            "example": "1 1234567890"
          },
          "dateOfBirth": {
            "type": "string",
            "description": "Customer date of birth (YYYY-MM-DD).",
            "example": "1990-12-01"
          }
        }
      },
      "ReturnUrls": {
        "required": [
          "failure",
          "success"
        ],
        "type": "object",
        "properties": {
          "success": {
            "type": "string",
            "description": "URL the customer is redirected to after a successful transaction.",
            "example": "https://merchant.example.com/success"
          },
          "failure": {
            "type": "string",
            "description": "URL the customer is redirected to after a failed transaction.",
            "example": "https://merchant.example.com/failure"
          }
        },
        "description": "Return URLs after the transaction is finished. A redirect does not confirm the final status; use webhooks or the GET transaction endpoint."
      },
      "PayInStatusWithReason": {
        "type": "object",
        "description": "PayIn transaction status with a detailed reason.",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Human-readable reason for the current status."
          },
          "detailedStatus": {
            "type": "string",
            "description": "Detailed status code. See the Transaction Lifecycle guide for meanings.",
            "enum": [
              "GENERAL_DECLINE",
              "BANK_ISSUES",
              "PSP_ISSUES",
              "CUSTOMER_ISSUES",
              "CVV_INVALID",
              "CARD_EXPIRED",
              "CARD_BLOCKED",
              "CARD_NOT_SUPPORTED",
              "NO_PROVIDER_AVAILABLE",
              "OTHER",
              "PROVIDER_NOT_SUITABLE",
              "PROVIDER_NOT_IN_ROUTE",
              "FRAUD_SCORE_ABOVE_THRESHOLD",
              "BLACKLISTED",
              "BLOCKED_CARD",
              "BLOCKED_CUSTOMER",
              "INVALID_CREDENTIALS",
              "AUTHENTICATION_FAILED",
              "ACCESS_DENIED",
              "CARD_DECLINED",
              "TRANSACTION_NOT_ALLOWED",
              "VALIDATION_ERROR",
              "INVALID_CARD_NUMBER",
              "INVALID_EXPIRY_DATE",
              "CVV_MISMATCH",
              "SYSTEM_ERROR",
              "DUPLICATE_TRANSACTION",
              "MARKED_AS_FRAUD",
              "PSP_UNREACHABLE",
              "INVALID_REQUEST_FORMAT",
              "OTHER_FAILURES",
              "UNMAPPED_ERRORS",
              "INSUFFICIENT_FUNDS",
              "THREE_DS_NOT_SUPPORTED",
              "TRANSACTION_TIMEOUT",
              "REFUND_ERROR",
              "REFUND_ALREADY_PROCESSED",
              "PARTIAL_REFUND_NOT_ALLOWED"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "CREATED",
              "PENDING",
              "PENDING_3DS",
              "SUCCESS",
              "REFUNDED",
              "PARTIALLY_REFUNDED",
              "DECLINED",
              "FAILED",
              "TIMEOUT",
              "REFUND_FAILED",
              "REFUND_PENDING"
            ]
          }
        }
      },
      "IpInfo": {
        "type": "object",
        "description": "IP geolocation and network information for the transaction.",
        "properties": {
          "country": {
            "type": "string"
          },
          "asn": {
            "type": "string"
          },
          "vpn": {
            "type": "boolean"
          },
          "proxy": {
            "type": "boolean"
          },
          "anonymousIp": {
            "type": "boolean"
          }
        }
      },
      "ProxyDetectionResponse": {
        "type": "object",
        "description": "Proxy, VPN and Tor detection signals for the transaction.",
        "properties": {
          "proxy": {
            "type": "boolean"
          },
          "host": {
            "type": "string"
          },
          "ISP": {
            "type": "string"
          },
          "Organization": {
            "type": "string"
          },
          "ASN": {
            "type": "integer",
            "format": "int32"
          },
          "country_code": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "latitude": {
            "type": "number",
            "format": "float"
          },
          "longitude": {
            "type": "number",
            "format": "float"
          },
          "zip_code": {
            "type": "string"
          },
          "is_crawler": {
            "type": "boolean"
          },
          "connection_type": {
            "type": "string"
          },
          "recent_abuse": {
            "type": "boolean"
          },
          "abuse_velocity": {
            "type": "string"
          },
          "bot_status": {
            "type": "boolean"
          },
          "vpn": {
            "type": "boolean"
          },
          "tor": {
            "type": "boolean"
          },
          "active_vpn": {
            "type": "boolean"
          },
          "active_tor": {
            "type": "boolean"
          },
          "mobile": {
            "type": "boolean"
          },
          "fraud_score": {
            "type": "number",
            "format": "float"
          },
          "frequent_abuser": {
            "type": "boolean"
          },
          "high_risk_attacks": {
            "type": "boolean"
          },
          "shared_connection": {
            "type": "boolean"
          },
          "dynamic_connection": {
            "type": "boolean"
          },
          "security_scanner": {
            "type": "boolean"
          },
          "trusted_network": {
            "type": "boolean"
          },
          "request_id": {
            "type": "string"
          },
          "operating_system": {
            "type": "string"
          },
          "browser": {
            "type": "string"
          },
          "device_brand": {
            "type": "string"
          },
          "device_model": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "FirstSeen": {
        "type": "object",
        "properties": {
          "human": {
            "type": "string"
          },
          "timestamp": {
            "type": "integer",
            "format": "int64"
          },
          "iso": {
            "type": "string"
          }
        }
      },
      "DomainAge": {
        "type": "object",
        "properties": {
          "human": {
            "type": "string"
          },
          "timestamp": {
            "type": "integer",
            "format": "int64"
          },
          "iso": {
            "type": "string"
          }
        }
      },
      "EmailValidationResponse": {
        "type": "object",
        "description": "Email validation and risk signals for the transaction.",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "disposable": {
            "type": "boolean"
          },
          "timed_out": {
            "type": "boolean"
          },
          "deliverability": {
            "type": "string"
          },
          "catch_all": {
            "type": "boolean"
          },
          "leaked": {
            "type": "boolean"
          },
          "suspect": {
            "type": "boolean"
          },
          "smtp_score": {
            "type": "integer",
            "format": "int32"
          },
          "overall_score": {
            "type": "integer",
            "format": "int32"
          },
          "first_name": {
            "type": "string"
          },
          "common": {
            "type": "boolean"
          },
          "generic": {
            "type": "boolean"
          },
          "dns_valid": {
            "type": "boolean"
          },
          "honeypot": {
            "type": "boolean"
          },
          "spam_trap_score": {
            "type": "string"
          },
          "recent_abuse": {
            "type": "boolean"
          },
          "fraud_score": {
            "type": "number",
            "format": "float"
          },
          "frequent_complainer": {
            "type": "boolean"
          },
          "suggested_domain": {
            "type": "string"
          },
          "domain_velocity": {
            "type": "string"
          },
          "domain_trust": {
            "type": "string"
          },
          "user_activity": {
            "type": "string"
          },
          "mx_records": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "a_records": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "risky_tld": {
            "type": "boolean"
          },
          "spf_record": {
            "type": "boolean"
          },
          "dmarc_record": {
            "type": "boolean"
          },
          "first_seen": {
            "$ref": "#/components/schemas/FirstSeen"
          },
          "domain_age": {
            "$ref": "#/components/schemas/DomainAge"
          },
          "sanitized_email": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "PhoneValidationResponse": {
        "type": "object",
        "description": "Phone validation and risk signals for the transaction.",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          },
          "formatted": {
            "type": "string"
          },
          "local_format": {
            "type": "string"
          },
          "fraud_score": {
            "type": "integer",
            "format": "int32"
          },
          "recent_abuse": {
            "type": "boolean"
          },
          "VOIP": {
            "type": "boolean"
          },
          "prepaid": {
            "type": "boolean"
          },
          "risky": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "carrier": {
            "type": "string"
          },
          "line_type": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "accurate_country_code": {
            "type": "boolean"
          },
          "zip_code": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "dialing_code": {
            "type": "integer",
            "format": "int32"
          },
          "do_not_call": {
            "type": "boolean"
          },
          "leaked": {
            "type": "boolean"
          },
          "spammer": {
            "type": "boolean"
          },
          "active_status": {
            "type": "string"
          },
          "user_activity": {
            "type": "string"
          },
          "mcc": {
            "type": "string"
          },
          "mnc": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          },
          "request_id": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "TransactionMetadata": {
        "type": "object",
        "properties": {
          "ipAddress": {
            "type": "string",
            "description": "Customer IP address recorded for the transaction."
          },
          "ipInfo": {
            "$ref": "#/components/schemas/IpInfo"
          },
          "deviceType": {
            "type": "string",
            "description": "Device type inferred for the transaction.",
            "enum": [
              "MOBILE",
              "DESKTOP",
              "TABLET",
              "UNKNOWN"
            ]
          },
          "proxyDetection": {
            "$ref": "#/components/schemas/ProxyDetectionResponse"
          },
          "emailValidation": {
            "$ref": "#/components/schemas/EmailValidationResponse"
          },
          "phoneValidation": {
            "$ref": "#/components/schemas/PhoneValidationResponse"
          }
        },
        "description": "Transaction metadata"
      },
      "PayInTransaction": {
        "required": [
          "amount",
          "createdAt",
          "currency",
          "customerId",
          "id",
          "initialAmount",
          "initialCurrency",
          "merchantId",
          "orderId",
          "returnUrls",
          "status",
          "updatedAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the pay-in transaction.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "amount": {
            "type": "number",
            "description": "Processed pay-in amount.",
            "example": 100
          },
          "merchantId": {
            "type": "string",
            "description": "Unique identifier for the merchant.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "customerId": {
            "type": "string",
            "description": "Omno customer ID.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "orderId": {
            "type": "string",
            "description": "Merchant-specified order identifier.",
            "example": "order-2026-000201"
          },
          "currency": {
            "type": "string",
            "description": "Processed pay-in currency (may differ from `initialCurrency` after conversion).",
            "example": "EUR"
          },
          "status": {
            "type": "string",
            "description": "PayIn transaction status.",
            "example": "SUCCESS",
            "enum": [
              "CREATED",
              "PENDING",
              "PENDING_3DS",
              "SUCCESS",
              "REFUNDED",
              "PARTIALLY_REFUNDED",
              "DECLINED",
              "FAILED",
              "TIMEOUT",
              "REFUND_FAILED",
              "REFUND_PENDING"
            ]
          },
          "initialAmount": {
            "type": "number",
            "description": "Requested pay-in amount.",
            "example": 100
          },
          "initialCurrency": {
            "type": "string",
            "description": "Requested pay-in currency.",
            "example": "EUR"
          },
          "routerId": {
            "type": "string",
            "description": "Router the transaction was processed through."
          },
          "returnUrls": {
            "$ref": "#/components/schemas/ReturnUrls"
          },
          "cardId": {
            "type": "string",
            "description": "Unique identifier for the card, if the card was saved.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "cardMask": {
            "type": "string",
            "description": "Masked card number, if a card was used.",
            "example": "1234 56** **** 1234"
          },
          "cardBrand": {
            "type": "string",
            "description": "Card brand, if a card was used.",
            "example": "VISA"
          },
          "cardHash": {
            "type": "string",
            "description": "Card hash, if a card was used.",
            "example": "7094c34678b3a4e29bcb5149266d1c811de2b6fc9370be9d5acdd7a334d8852b"
          },
          "merchantPspId": {
            "type": "string",
            "description": "ID of the PSP that processed the transaction. For test transactions this equals the fake PSP ID provided by Omno — never credit or debit real balances for these.",
            "example": "944732c4-608c-441a-a913-79478b91f76e"
          },
          "pspTransactionId": {
            "type": "string",
            "description": "PSP-side transaction ID.",
            "example": "944732c4-608c-441a-a913-79478b91f76e"
          },
          "statusReason": {
            "$ref": "#/components/schemas/PayInStatusWithReason"
          },
          "previousTransactionCount": {
            "type": "integer",
            "description": "Number of previous transactions the customer made in your system.",
            "format": "int32"
          },
          "metadata": {
            "$ref": "#/components/schemas/TransactionMetadata"
          },
          "transactionType": {
            "type": "string",
            "description": "Transaction type.",
            "example": "CARD",
            "enum": [
              "CARD",
              "BANK",
              "WALLET",
              "CASH",
              "CRYPTO",
              "OTHER"
            ]
          },
          "additionalData": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "description": "User-provided additional data for Alternative Payment Methods."
            },
            "description": "User-provided additional data for Alternative Payment Methods."
          },
          "pspAdditionalData": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "description": "Additional data obtained from the PSP during processing."
            },
            "description": "Additional data obtained from the PSP during processing."
          },
          "createdAt": {
            "type": "string",
            "description": "Transaction creation time in UTC.",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "description": "Transaction last update time in UTC.",
            "format": "date-time"
          }
        }
      },
      "PayoutStatusWithReason": {
        "type": "object",
        "description": "Payout transaction status with a detailed reason.",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Human-readable reason for the current status."
          },
          "detailedStatus": {
            "type": "string",
            "description": "Detailed status code. See the Transaction Lifecycle guide for meanings.",
            "enum": [
              "NO_PROVIDER_AVAILABLE",
              "AMOUNT_TOO_LOW",
              "AMOUNT_TOO_HIGH",
              "OTHER",
              "PROVIDER_NOT_SUITABLE",
              "PROVIDER_NOT_IN_ROUTE",
              "FRAUD_SCORE_ABOVE_THRESHOLD",
              "BLACKLISTED",
              "BLOCKED_CARD",
              "BLOCKED_CUSTOMER",
              "REJECTED_BY_MERCHANT",
              "PSP_CHANGED_AFTER_APPROVAL",
              "INVALID_CREDENTIALS",
              "AUTHENTICATION_FAILED",
              "ACCESS_DENIED",
              "CARD_DECLINED",
              "TRANSACTION_NOT_ALLOWED",
              "VALIDATION_ERROR",
              "INVALID_CARD_NUMBER",
              "INVALID_EXPIRY_DATE",
              "CVV_MISMATCH",
              "SYSTEM_ERROR",
              "DUPLICATE_TRANSACTION",
              "MARKED_AS_FRAUD",
              "PSP_UNREACHABLE",
              "INVALID_REQUEST_FORMAT",
              "OTHER_FAILURES",
              "UNMAPPED_ERRORS",
              "INSUFFICIENT_FUNDS",
              "TRANSACTION_REJECTED_BY_PROVIDER"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "CREATED",
              "WAITING_FOR_CONFIRMATION",
              "PENDING",
              "PROCESSED",
              "REJECTED",
              "FAILED",
              "TIMEOUT"
            ]
          }
        }
      },
      "Browser": {
        "type": "object",
        "description": "Customer browser information, collected client-side and required for Direct Link processing (used for 3DS and fraud checks).",
        "properties": {
          "acceptHeader": {
            "type": "string",
            "description": "Value of the browser `Accept` header.",
            "example": "text/html,application/xhtml+xml"
          },
          "userAgent": {
            "type": "string",
            "description": "Browser user-agent string (`navigator.userAgent`).",
            "example": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
          },
          "language": {
            "type": "string",
            "description": "Browser language (`navigator.language`).",
            "example": "en-US"
          },
          "timeZoneOffset": {
            "type": "integer",
            "format": "int32",
            "description": "Time-zone offset in minutes (`Date.getTimezoneOffset()`).",
            "example": -60
          },
          "timeZone": {
            "type": "string",
            "description": "IANA time-zone name.",
            "example": "Europe/Berlin"
          },
          "colorDepth": {
            "type": "integer",
            "format": "int32",
            "description": "Screen color depth in bits (`screen.colorDepth`).",
            "example": 24
          },
          "screenHeight": {
            "type": "integer",
            "format": "int32",
            "description": "Screen height in pixels (`screen.height`).",
            "example": 1080
          },
          "screenWidth": {
            "type": "integer",
            "format": "int32",
            "description": "Screen width in pixels (`screen.width`).",
            "example": 1920
          },
          "windowHeight": {
            "type": "integer",
            "format": "int32",
            "description": "Browser window inner height in pixels (`window.innerHeight`).",
            "example": 969
          },
          "windowWidth": {
            "type": "integer",
            "format": "int32",
            "description": "Browser window inner width in pixels (`window.innerWidth`).",
            "example": 1920
          },
          "javaEnabled": {
            "type": "boolean",
            "description": "Whether Java is enabled (`navigator.javaEnabled()`).",
            "example": false
          },
          "javascriptEnabled": {
            "type": "boolean",
            "description": "Whether JavaScript is enabled. Always `true` when collected in-browser.",
            "example": true
          },
          "customerIp": {
            "type": "string",
            "description": "Customer IP address.",
            "example": "203.0.113.10"
          }
        }
      },
      "PayoutTransaction": {
        "required": [
          "amount",
          "createdAt",
          "currency",
          "customerId",
          "id",
          "initialAmount",
          "initialCurrency",
          "merchantId",
          "orderId",
          "status",
          "updatedAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the payout transaction.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "amount": {
            "type": "number",
            "description": "Processed payout amount.",
            "example": 100
          },
          "merchantId": {
            "type": "string",
            "description": "Unique identifier for the merchant.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "customerId": {
            "type": "string",
            "description": "Omno customer ID.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "orderId": {
            "type": "string",
            "description": "Merchant-specified order identifier.",
            "example": "order-2026-000123"
          },
          "currency": {
            "type": "string",
            "description": "Processed payout currency (may differ from `initialCurrency` after conversion).",
            "example": "EUR"
          },
          "status": {
            "type": "string",
            "description": "Payout transaction status.",
            "example": "PROCESSED",
            "enum": [
              "CREATED",
              "WAITING_FOR_CONFIRMATION",
              "PENDING",
              "PROCESSED",
              "REJECTED",
              "FAILED",
              "TIMEOUT"
            ]
          },
          "initialAmount": {
            "type": "number",
            "description": "Requested payout amount.",
            "example": 100
          },
          "initialCurrency": {
            "type": "string",
            "description": "Requested payout currency.",
            "example": "EUR"
          },
          "routerId": {
            "type": "string",
            "description": "Router the transaction was processed through."
          },
          "cardId": {
            "type": "string",
            "description": "Unique identifier for the card, if a saved card was used."
          },
          "cardMask": {
            "type": "string",
            "description": "Masked card number, if a card was used.",
            "example": "1234 56** **** 1234"
          },
          "cardBrand": {
            "type": "string",
            "description": "Card brand, if a card was used.",
            "example": "VISA"
          },
          "cardHash": {
            "type": "string",
            "description": "Card hash, if a card was used."
          },
          "predictedPspId": {
            "type": "string",
            "description": "PSP predicted by routing before processing."
          },
          "processorPspId": {
            "type": "string",
            "description": "ID of the PSP that processed the transaction. For test transactions this equals the fake PSP ID provided by Omno — never credit or debit real balances for these.",
            "example": "944732c4608c441aa91379478b91f76e"
          },
          "pspTransactionId": {
            "type": "string",
            "description": "PSP-side transaction ID."
          },
          "previousTransactionCount": {
            "type": "integer",
            "format": "int32",
            "description": "Number of previous transactions the customer made in your system."
          },
          "statusReason": {
            "$ref": "#/components/schemas/PayoutStatusWithReason"
          },
          "metadata": {
            "$ref": "#/components/schemas/TransactionMetadata"
          },
          "transactionType": {
            "type": "string",
            "description": "Transaction type.",
            "example": "BANK",
            "enum": [
              "CARD",
              "BANK",
              "WALLET",
              "CASH",
              "CRYPTO",
              "OTHER"
            ]
          },
          "browser": {
            "$ref": "#/components/schemas/Browser"
          },
          "additionalData": {
            "type": "object",
            "description": "Method-specific data provided when processing the payout.",
            "additionalProperties": {
              "type": "object"
            }
          },
          "pspAdditionalData": {
            "type": "object",
            "description": "Additional data returned by the PSP during processing.",
            "additionalProperties": {
              "type": "object"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "Transaction creation time in UTC."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Transaction last update time in UTC."
          }
        }
      }
    }
  }
}