diff --git a/account/adding-safe-owner.mdx b/account/adding-safe-owner.mdx
deleted file mode 100644
index 49b5d5e..0000000
--- a/account/adding-safe-owner.mdx
+++ /dev/null
@@ -1,63 +0,0 @@
----
-title: "Managing Safe Ownership"
-description: "Add a new owner to a Gnosis Pay Safe Account"
----
-
-Adding a new owner to a Gnosis Pay Safe registers that account as a **Delay Module owner**.
-Only Delay Module owners can approve and execute on-chain transactions.
-
-
-**Important distinction:**
-- **Authenticated wallets** are linked to a Gnosis Pay user for API access (via SIWE and JWT).
-- **Safe owners (Delay Module owners)** are accounts explicitly added on-chain to the Safe.
-Authenticated wallets do **not** become Safe owners unless they are also as owners for the safe.
-
-
-This guide walks through the process of adding an additional Safe owner. Once complete, the new owner will be able to approve and execute transactions through the Delay Module.
-
-
-
- Follow the [authentication flow](https://docs.gnosispay.com/auth) to obtain a JWT token for the Gnosis Pay user.
-
-
-
- Call [this endpoint](https://docs.gnosispay.com/api-reference/safe-owners/get-typed-data-for-adding-a-new-safe-owner) to receive the typed data.
- Sign the typed data with the current Safe owner’s key to produce a signature.
-
- ```bash
- curl --request GET \
- --url https://api.gnosispay.com/api/v1/owners/add/transaction-data \
- --header "Authorization: Bearer "
- ```
-
-
-
- Send the new owner’s address, the signature, and the signed message to [this endpoint](https://docs.gnosispay.com/api-reference/safe-owners/add-a-new-owner-to-the-safe).
-
- ```bash
- curl --request POST \
- --url https://api.gnosispay.com/api/v1/owners \
- --header "Authorization: Bearer " \
- --header "Content-Type: application/json" \
- --data '{
- "newOwner": "0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382",
- "signature": "0x1234567890abcdef...",
- "message": {
- "salt": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
- "data": "0xa9059cbb0000000000000000000000003270bf32ab647e90ef94a026c70aa1daaaada2382"
- }
- }'
- ```
- The operation is processed through the Delay Relay and executes after a 3-minute delay.
-
-
-
- Confirm that the new owner was added to the Delay Module by checking the [Safe’s owner list](https://docs.gnosispay.com/api-reference/safe-owners/get-the-list-of-safe-owners).
-
- ```bash
- curl --request GET \
- --url https://api.gnosispay.com/api/v1/owners \
- --header "Authorization: Bearer "
- ```
-
-
diff --git a/account/index.mdx b/account/index.mdx
deleted file mode 100644
index 7bfb23d..0000000
--- a/account/index.mdx
+++ /dev/null
@@ -1,108 +0,0 @@
----
-title: "Accounts on Gnosis Pay"
-description: "How the Gnosis Pay Safe works"
----
-
-When a user signs up for Gnosis Pay, a new **Gnosis Pay Safe** a smart contract wallet is created on-chain.
-This Safe holds the user’s funds and is controlled only by its **owners**.
-
-A Gnosis Pay Safe owner can be either:
-- an **EOA (Externally Owned Account)**, or
-- another **smart wallet** (e.g. a Safe) whose owners may use passkeys, EOAs, or other signers.
-
-Funds in a Gnosis Pay Safe are never held by Gnosis Pay or any third party; ownership and control remain entirely with the Safe owners.
-
-
-
-
-
----
-
-## Authenticating sessions with wallets
-
-To access the Gnosis Pay dashboard or APIs, a wallet must authenticate using [Sign-In With Ethereum (SIWE)](https://docs.login.xyz/).
-After SIWE, a JWT token is issued and used to authorize API calls (e.g. ordering cards, fetching user info, or linking additional authenticated wallets).
-
-Authenticated wallets are used **only for login and API sessions**. They do not perform on-chain actions and may or may not overlap with the Safe owners.
-
-
-The first wallet connected during setup is automatically registered as both an **authenticated wallet** and the **initial Safe owner** (via the Delay Module).
-
-
-Follow the guide on [adding an authenticated wallet](account/update-authenticated-account) for step-by-step instructions.
-
----
-
-## Safe Smart Account
-
-Each Gnosis Pay user is assigned a **Safe Smart Account**, a self-custodied smart contract wallet deployed on Gnosis Chain (L1).
-Currently, a new Safe is deployed for every user. Support for connecting an existing Safe multisig is planned.
-
-### What is a smart contract wallet?
-
-Smart contract wallets are contracts that manage assets on-chain with programmable rules.
-They enable advanced security and automation beyond EOAs.
-
-[Safe](https://safe.global/) is the leading smart contract wallet, securing over $70B in assets.
-
-### Exploring the Safe setup
-
-Users can view their Safe configuration in the [Safe web app](https://app.safe.global/) via the Zodiac app:
-
-1. Open the Gnosis Pay Dashboard.
-2. Click **“View all transactions here”** to open the Safe web app.
-3. In the sidebar, select **Applications**.
-4. Search for **Zodiac**.
-
-The **Roles Module** and **Delay Module** are open-source contracts licensed under LGPL 3.0.
-
----
-
-## Modules
-
-Modules extend Safe functionality with custom logic.
-In Gnosis Pay, modules enforce spending rules and transaction flows while keeping user funds in self-custody.
-
-These modules follow the [Zodiac standard](https://gnosisguild.org/zodiac/) developed by Gnosis Guild.
-
----
-
-## Roles Module
-
-The Roles Module enforces which actions Gnosis Pay can perform on behalf of the user. It defines:
-
-1. **Token used** → which token Gnosis Pay can spend.
-2. **Daily limit** → maximum amount spendable per day.
-3. **Recipient address** → destination for allowed transfers (e.g. the issuer’s settlement Safe).
-4. **Role delegation** → assigns these permissions to Gnosis Pay.
-
-Only Safe owners can update these rules.
-For example, a user may adjust the daily spending limit at any time.
-
----
-
-## Delay Module
-
-The Delay Module enforces a **3-minute delay** for all non-card transactions (e.g. transfers, deposits).
-This ensures funds remain available for card payments and prevents race conditions.
-
-
-During the 3-minute delay, the card is paused if any non-card transactions are pending.
-
-
-The Delay Module also ensures the user’s EOA retains ultimate control.
-During activation, the EOA becomes an indirect Safe owner via the Delay Module.
-
-⚠️ Reconfiguring or removing the Delay Module may prevent Gnosis Pay from functioning properly.
-
----
-
-## What happens if I lose access to my EOA Wallet?
-
-If you’ve forgotten the password to your EOA Wallet, you can regain access using its seed phrase.
-
-
-However, if you’ve lost access to the seed phrase and cannot regain access to the EOA, you will also lose access to the Safe if it’s the only owner.
-
-
-**To mitigate this risk, consider using a [Safe](https://safe.global/) with multiple owners instead of an EOA.**
\ No newline at end of file
diff --git a/account/update-authenticated-account.mdx b/account/update-authenticated-account.mdx
deleted file mode 100644
index 347b59d..0000000
--- a/account/update-authenticated-account.mdx
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: "Adding a new wallet for authentication"
-description: "Link an additional wallet address to a Gnosis Pay user"
----
-
-A Gnosis Pay user can have multiple authenticated wallets attached to their account.
-Authenticated wallets are used to sign in via SIWE and to start new API sessions.
-
-
-
- Follow the [authentication flow](https://docs.gnosispay.com/auth) to obtain a JWT token for the Gnosis Pay user.
-
-
-
- Make a POST call to [this endpoint](https://docs.gnosispay.com/api-reference/account-management/create-a-new-eoa-account-for-the-current-user) with the address to add.
-
- ```bash
- curl --request POST \
- --url https://api.gnosispay.com/api/v1/eoa-accounts \
- --header "Authorization: Bearer " \
- --header "Content-Type: application/json" \
- --data '{
- "address": "0x1234567890abcdef1234567890abcdef12345678"
- }'
- ```
-
-
-
- Call the [list accounts endpoint](https://docs.gnosispay.com/api-reference/account-management/retrieve-the-eoa-accounts-for-the-current-user).
- The new address should appear in the response.
-
- ```bash
- curl --request GET \
- --url https://api.gnosispay.com/api/v1/eoa-accounts \
- --header "Authorization: Bearer "
- ```
-
-
-
-
-- Adding an **authenticated wallet** only links it to a Gnosis Pay user for login and API sessions.
-- An authenticated wallet is **not automatically a Safe owner**.
-- Only Safe owners (EOAs or smart wallets added to the Safe) can interact with the Delay Module or execute on-chain actions.
-- Authenticated wallets can use the API (e.g. place card orders, fetch user info) but **cannot control funds** unless also added as Safe owners.
-
diff --git a/api-reference/auth-app.mdx b/api-reference/auth-app.mdx
deleted file mode 100644
index 8949e78..0000000
--- a/api-reference/auth-app.mdx
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Authentication Helper App
-description: Use this app to generate and sign a message using your ethereum wallet.
----
-
-export const AuthApp = () => {
- return (
-
-
-
-
-
- )
-}
-
-
-
-You can also open this app in a new tab.
-
-
-
diff --git a/api-reference/intro.mdx b/api-reference/intro.mdx
deleted file mode 100644
index 65e95aa..0000000
--- a/api-reference/intro.mdx
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: API Reference Introduction
-description: General guidelines on how to integrate with GnosisPay.
----
-
-Gnosis Pay offers an HTTP JSON API, fully documented using [OpenAPI—you can find our specification here](https://api.gnosispay.com/api-docs/spec.json). This API reference is auto-generated from our OpenAPI spec, and you can also use the JSON file to generate client code in various programming languages.
-
-Most API endpoints require authentication with a [JWT obtained via Sign-In with Ethereum (SIWE)](/auth). For your convenience, we provide a [helper app](/api-reference/auth-app) within these docs to help you generate a token and sign Safe transactions.
-
-To make API requests using the API Reference playground, simply paste your token into the Authorization Header field.
diff --git a/auth.mdx b/auth.mdx
deleted file mode 100644
index 789380f..0000000
--- a/auth.mdx
+++ /dev/null
@@ -1,85 +0,0 @@
----
-title: Authentication Flow
-description: Use Sign-In with Ethereum (SIWE) to authenticate API requests.
----
-
-Our authentication system uses Sign-In with Ethereum (SIWE) to generate a `jwt` to interact with our API.
-This means you don't need to handle the storage of a powerful API key or spend hours configuring granular permissions.
-
-
-**For Partners**: If you're building a partner integration, make sure to register your domains through the [Partners Dashboard](https://partners.gnosispay.com/) during signup. This ensures your domains are whitelisted for SIWE authentication and prevents authentication failures.
-
-
-
-## Authentication Process
-
-
-
-Before initiating authentication, [the application must request a nonce](/api-reference/authentication/generate-nonce).
-Your application then presents this nonce to the user for signing as part of the SIWE flow.
-
-```bash cURL
-curl -X GET /api/v1/auth/nonce
-```
-
-
-Our API accepts signatures from Externally Owned Accounts (EOAs) and Smart Accounts (EIP-1271).
-
-
-The signer must be an owner of a Gnosis Pay account.
-Non-registered users will receive `401 Unauthorized` on most authenticated routes
-
-
-
-
-
-**JWT length validity**
-
-- **Default Validity**: JWT tokens are valid for the duration specified in `ttlInSeconds` during SIWE authentication
-- **Minimum Duration**: 1 hour
-- **Maximum Duration**: 24 hours
-
-
-After the message is signed, you need to submit both the message and the signature to [retrieve an Access Token](/api-reference/authentication/verify-siwe-signature):
-```bash cURL
-curl -X POST /api/v1/auth/challenge \
- -H "Content-Type: application/json" \
- -d '{
- "message": "string",
- "signature": "string",
- "ttlInSeconds": 36000
- }'
-```
-
-
-
-
-
-
-**Domain Whitelisting**: Gnosis Pay validates SIWE domains against a whitelist for security.
-
-- **localhost**: `localhost` (with or without ports like `localhost:3000`) is automatically allowed for local development
-- **Production domains**: All production and staging domains must be registered through the [Partners Dashboard](https://partners.gnosispay.com/) during signup
-- **127.0.0.1**: Avoid using `127.0.0.1` in SIWE messages as it may cause firewall blocks and "WAFForbidden" errors
-
-Only whitelisted domains (plus localhost) will be accepted for SIWE authentication.
-
-
-Upon successful verification, a `jwt` is generated.
-This `jwt` must be included in the Authorization header of all subsequent HTTP requests to authenticate with the Gnosis Pay API:
-
-```bash
-Authorization: Bearer {jwt}
-```
-
-## Details about the Access Token
-
-A `jwt` is generated upon successful Sign-In with Ethereum (SIWE) verification and can remain valid for up to **24 hours**, depending on the **`ttlInSeconds`** parameter passed to SIWE, with a minimum validity period of 1 hour.
-
-To enhance security and prevent replay attacks, each authentication attempt requires a new and unique nonce.
-
-Always ensure that the `jwt` is valid before making API requests.
-If an API request returns a 401 Unauthorized response due to an expired token,
-your application must restart the authentication process, which requires user interaction.
-This means the application must request a new nonce, prompt the user to sign the message,
-and then submit the signature for verification to generate a fresh `jwt`.
diff --git a/cards/assets/PSE-diagram.png b/cards/assets/PSE-diagram.png
deleted file mode 100644
index 85225d0..0000000
Binary files a/cards/assets/PSE-diagram.png and /dev/null differ
diff --git a/cards/assets/card-order-flow.png b/cards/assets/card-order-flow.png
deleted file mode 100644
index fc21d4e..0000000
Binary files a/cards/assets/card-order-flow.png and /dev/null differ
diff --git a/cards/card-order-state-transitions.mdx b/cards/card-order-state-transitions.mdx
deleted file mode 100644
index 688c41d..0000000
--- a/cards/card-order-state-transitions.mdx
+++ /dev/null
@@ -1,183 +0,0 @@
----
-title: Card Order State Transitions
-description: "Understanding the card order state transitions"
----
-Below is the complete state transition diagram and detailed explanations.
-
-### State Transition Diagram
-
-```mermaid
- stateDiagram-v2
- [*] --> PENDINGTRANSACTION : Create Order
-
- PENDINGTRANSACTION --> READY : Pay (free or paid)
- PENDINGTRANSACTION --> TRANSACTIONCOMPLETE : Payment Complete
- PENDINGTRANSACTION --> CANCELLED : Cancel
- PENDINGTRANSACTION --> FAILEDTRANSACTION : Payment Failed
-
- TRANSACTIONCOMPLETE --> CONFIRMATIONREQUIRED : Request Confirmation
-
- CONFIRMATIONREQUIRED --> READY : Confirm Ready (SOF + Phone + Address)
-
- READY --> CARDCREATED : Create Card (Physical/Virtual)
-
- CARDCREATED --> [*] : Order Complete
- CANCELLED --> [*] : Order Cancelled
- FAILEDTRANSACTION --> [*] : Order Failed
-
- note right of PENDINGTRANSACTION
- Initial state when order is created
- end note
-
- note right of READY
- Ready for card creation All requirements met
- end note
-
- note right of CARDCREATED
- Card successfully created Order fulfilled
- end note
-```
-
-
-
-### Card Order States
-
-#### Core States
-
-**`PENDINGTRANSACTION`** - *Initial State*
-- **Description**: Order created, awaiting payment or confirmation
-- **Next States**: `READY`, `TRANSACTIONCOMPLETE`, `CANCELLED`, `FAILEDTRANSACTION`
-- **User Actions**: Attach transaction, confirm payment, cancel order
-
-**`TRANSACTIONCOMPLETE`** - *Payment Processed*
-- **Description**: Payment transaction completed but requires additional verification
-- **Next States**: `CONFIRMATIONREQUIRED`
-- **System Actions**: Automatic transition when additional verification needed
-
-**`CONFIRMATIONREQUIRED`** - *Verification Needed*
-- **Description**: Additional user verification required (SOF, phone, address)
-- **Next States**: `READY`
-- **Requirements**: Phone verified, SOF completed, address provided
-
-**`READY`** - *Ready for Card Creation*
-- **Description**: All requirements met, ready to create physical/virtual card
-- **Next States**: `CARDCREATED`
-- **User Actions**: Create card with PIN (physical) or without PIN (virtual)
-
-#### Terminal States
-
-**`CARDCREATED`** - *Success*
-- **Description**: Card successfully created and ready for use
-- **Next States**: None (terminal state)
-- **Note**: Virtual cards are immediately active; physical cards need activation
-
-**`CANCELLED`** - *Cancelled*
-- **Description**: Order cancelled by user or system
-- **Next States**: None (terminal state)
-- **Note**: Only possible from `PENDINGTRANSACTION` state
-
-**`FAILEDTRANSACTION`** - *Payment Failed*
-- **Description**: Payment processing failed
-- **Next States**: None (terminal state)
-- **Note**: User needs to create a new order
-
-### Transition Rules
-
-
-
-`PENDINGTRANSACTION` → `READY`:
-- Free card: `totalAmountEUR === totalDiscountEUR`
-- Paid card: Valid EURe payment to correct address
-- Transaction hash validation (if required)
-
-
-
-`TRANSACTIONCOMPLETE` → `CONFIRMATIONREQUIRED`:
-- Triggered when additional user verification is needed
-- System determines extra checks required
-
-
-
-`CONFIRMATIONREQUIRED` → `READY`:
-- User phone verified
-- Source of Funds (SOF) completed
-- Valid shipping address (for physical cards)
-
-
-
-`READY` → `CARDCREATED`:
-- KYC approved
-- Risk score: Green or Orange
-- For physical cards: Encrypted PIN required
-- For virtual cards: No PIN needed
-
-
-
-`PENDINGTRANSACTION` → `CANCELLED`:
-- Only from `PENDINGTRANSACTION` state
-- User-initiated or admin-initiated
-
-
-
-### Error Handling
-
-When implementing card order, consider these scenarios:
-
-**Invalid Transitions**
-Will throw TransitionError
-- Trying to cancel from READY state
-- Attempting to create card from `PENDINGTRANSACTION`
-- Any transition not defined in the state machine
-
-
-**Common Error Scenarios**
-- **Payment Issues**: Transaction hash already used, insufficient payment
-- **User Requirements**: Missing KYC, unverified phone, missing address
-- **System Issues**: Payment processor errors, card creation failures
-
-### Implementation Example
-
-```javascript
-// Check current order state before taking action
-const handleOrderAction = async (order, action) => {
- switch (order.status) {
- case 'PENDINGTRANSACTION':
- if (action === 'pay') {
- await confirmPayment(order.id);
- } else if (action === 'cancel') {
- await cancelOrder(order.id);
- }
- break;
-
- case 'READY':
- if (action === 'createCard') {
- await createCard(order.id, { setPin: !order.virtual });
- }
- break;
-
- case 'CARDCREATED':
- // Order complete - handle card activation if needed
- break;
-
- default:
- throw new Error(`Cannot perform ${action} on order with status ${order.status}`);
- }
-};
-```
-
-### Cancellable States
-
-Orders can only be cancelled from specific states. Use the `CANCELLABLE_ORDER_STATUSES` constant:
-
-```javascript
-const CANCELLABLE_ORDER_STATUSES = [
- 'PENDINGTRANSACTION',
- 'TRANSACTIONCOMPLETE',
- 'CONFIRMATIONREQUIRED',
- 'FAILEDTRANSACTION'
-];
-```
-
-
-**State Validation**: Always validate the current order state before attempting transitions. Invalid transitions will throw a `TransitionError` and return HTTP 422 status code.
-
diff --git a/cards/concepts.mdx b/cards/concepts.mdx
deleted file mode 100644
index b8ab122..0000000
--- a/cards/concepts.mdx
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: Cards Concepts
-description: "Core concepts for card management, PINs, and merchant categories"
----
-
-Cards are their own domain, with lots of edge cases all around and a unique set of terms.
-On this document, we aim to present the most common concepts related to operating cards
-and what to expect of them.
-
-This is not an extensive guide and we encourage you to use this document as a way to start
-your journey. Both VISA and Mastercard have great resources and guides that you can also use.
-
-
- For transaction-related concepts like payments, refunds, and reversals, see our dedicated
- [Card Transactions](/transactions) guide.
-
-
-## Card Lifecycle
-
-Cards go through several states during their lifetime:
-
-### Card States
-- **Inactive**: Card created but not yet activated
-- **Active**: Card activated and ready for use
-- **Frozen**: Temporarily disabled (can be unfrozen)
-- **Lost**: Reported as lost (requires replacement)
-- **Stolen**: Reported as stolen (requires replacement)
-- **Expired**: Past expiration date (requires replacement)
-
-### Card Activation
-New cards must be activated before first use. Activation typically involves:
-- Verifying cardholder identity
-- Setting initial PIN (if required)
-- Confirming card receipt
-- Enabling spending limits
-
-### Card Management Operations
-- **Freeze/Unfreeze**: Temporarily disable card usage
-- **Report Lost/Stolen**: Permanently disable and request replacement
-- **Update Limits**: Modify spending or withdrawal limits
-- **PIN Management**: Change or reset PIN
-
-## Disputes
-
-Disputes are used to recover funds for captured transactions. Their main use-case is to revert fraudulent transactions
-or problems with the product or service paid for. Fraud and non-fraud disputes have different requirements and rules,
-and undergo through different analysis to reach a conclusion.
-
-### Dispute Types
-- **Fraud disputes**: Unauthorized transactions
-- **Non-fraud disputes**: Issues with goods/services received
-- **Processing errors**: Technical or merchant errors
-
-### Dispute Process
-1. **Initiation**: Cardholder reports disputed transaction
-2. **Investigation**: Review transaction details and evidence
-3. **Provisional Credit**: Temporary refund while investigating
-4. **Resolution**: Final decision and permanent credit/debit
-
-## Card PINs
-
-Visa cards have 2 places to store the PIN - the first place is on the physical card chip, called the **offline PIN**, and the second is the **online PIN** that is stored in the bank's system. While these PINs usually have the same value, there can be cases where they differ, for instance when you change the card PIN.
-
-When paying at a point of sale (in a restaurant or in a shop), only the offline PIN may be verified, while ATMs usually connect to the bank network and check the online PIN. When using the PSE to change the PIN, only the online PIN is changed. At this point, the offline PIN is **not updated** since physical access to the card is needed to change the PIN on the chip. To update the offline PIN, you need to go to an ATM and perform any operation. ATM transactions always go online to the card issuer. This allows the issuer to send an "issuer script" to your card, which updates the offline PIN stored on the chip, synchronizing it with any recent PIN changes made online (with PSE). Without this synchronization, your offline PIN might be outdated and cause issues for transactions that rely on offline verification.
-
-## MCC: Merchant Category Code
-
-Merchant Category Codes (MCCs) are used to classify businesses based on the types of goods or services they provide.
-These codes are important as they are often used for calculating interchange fees, authorizing payments, and preventing fraud.
-Additionally, specific MCCs are required for particular functionalities.
diff --git a/cards/create-physical-cards.mdx b/cards/create-physical-cards.mdx
deleted file mode 100644
index 6ae1be3..0000000
--- a/cards/create-physical-cards.mdx
+++ /dev/null
@@ -1,110 +0,0 @@
----
-title: "Create Physical Cards"
-description: "Order physical cards for your Users."
----
-
-
-## Create Physical Card Process
-
-
-
-
-
-[This endpoint creates a new `CardOrder` with the status of `PENDINGTRANSACTION`](/api-reference/physical-card-order/create-physical-card-order):
-
-```bash cURL
-curl -X POST /api/v1/order/create
-```
-
-The Card Order is created with the following data:
-
-- A shipping address can be specified by filling the `shippingAddress` field, see [endpoint specifications](/api-reference/physical-card-order/create-physical-card-order). If not set, the KYC address will be used for shipping.
-- The total amount to be paid is set in EURe. The amount is 30.23.
-- A coupon code can be applied to reduce the amount to be paid, either at signup or in the next step
-
-
-
-
-[This endpoint attaches a coupon to the `CardOrder` with `orderId`](/api-reference/physical-card-order/attach-a-coupon-to-a-physical-card-order):
-
-```bash cURL
-curl -X POST /api/v1/order/{orderId}/attach-coupon
-```
-
-The coupon needs to be valid, otherwise an error is thrown.
-If the user has a coupon code both from the signup, and from this step, the one from the signup takes precedence.
-
-
-
-
-
-This is only needed if the card is not free. If `CardOrder.totalAmountEUR` is the same as the `CardOrder.totalDiscountEUR` then the card is considered free.
-
-
-[This endpoint allows setting a transaction hash to the specified `orderId`](/api-reference/physical-card-order/register-payment-for-a-physical-card-order).
-
-```bash cURL
-curl -X PUT /api/v1/order/{orderId}/attach-transaction \
--d '{
- "transactionHash": "0x..."
-}'
-```
-
-The transaction can only be used once across all card orders.
-
-
-
-
-
-This endpoint must be called even if the card is free. It moves the card order to the `READY` status.
-
-
-[To confirm the payment call this endpoint](/api-reference/physical-card-order/confirm-the-payment-for-a-physical-card-order):
-
-```bash cURL
-curl -X PUT /api/v1/order/{orderId}/confirm-payment
-```
-
-The conditions for the payment are:
-
-- In order to call this endpoint, the `CardOrder.status` needs to be `PENDINGTRANSACTION`.
-- If the card is not free, we check if a payment was done.
- - Token used for payment needs to be EURe `0xcB444e90D8198415266c6a2724b7900fb12FC56E`.
- - Payment was done to `0x3D4FD6a1A7a1382ae1d62C3DD7247254a0236847`.
- - The respective EURe amount was paid in that transaction hash (partial transfers are not supported).
-
-If all the conditions above are met, the `CardOrder.status` is set to `READY`.
-
-
-[Finally, you can create the Physical Card](/api-reference/physical-card-order/create-a-physical-card):
-
-```bash cURL
-curl -X POST /api/v1/order/:orderId/create-card
-```
-
-When successful, this endpoint returns the `cardToken` from the newly created card.
-
-In order to create a `Card` out of a `CardOrder` the following conditions need to be met:
-
-- No cards were created out of this `orderId`.
-- User needs to have a verified phone number.
-- User needs to have a name set.
-- User needs to be from a supported country.
-- User address needs to be set.
-- User needs to have an approved KYC.
-- The risk score needs to be Green or Orange based on the user's answers to the Source of funds questionnaire.
-- User needs to have the shipping details for the physical card order set.
- - The shipping details can be different from the KYC address, as long as it is in the same country.
- - Virtual cards do not require a shipping address.
-- The embossed name for the card needs to be set.
-
-
-
-The card PIN should be set immediately after the card is created via the Partner Secure Elements (PSE).
-Use the `cardToken` returned from the previous endpoint to set the PIN.
-If a PIN is not provided upon creation, a random one will be assigned.
-Changing this randomly assigned PIN requires the user to visit an ATM. Refer to the **[card PINs section](/cards#card-pins)** to learn more about the online and offline PINs.
-
-For detailed instructions about how to change the PIN, please refer to the [PSE SDK documentation](/cards/pse-integration).
-
-
diff --git a/cards/create-virtual-cards.mdx b/cards/create-virtual-cards.mdx
deleted file mode 100644
index a623642..0000000
--- a/cards/create-virtual-cards.mdx
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: Create Virtual Cards
-description: Virtual cards work either online or tap in presence (with Apple Pay and Google Pay).
----
-
-Virtual card orders have a **simplified flow** compared to physical cards, with these key differences:
-
-- No shipping address is required
-- The card is available immediately after order creation (no shipping delay)
-- Virtual cards can be used for online transactions immediately
-- Thanks to Google and Apple Pay (some regions are not yet available), the card can be used for in-person transactions immediately.
-- No PIN is required; the user's phone number is used as second factor authentication for some online payments
-- **Cards are automatically created and activated when the order is placed**
-
-## How to create a Virtual Card
-
-[This endpoint allows you to issue a virtual card directly](/api-reference/card-management/create-a-virtual-card):
-
-```bash cURL
-curl -X POST /api/v1/cards/virtual
-```
-
-Virtual cards are free and activated immediately. No shipping address or payment validation required.
-
-
-
-**Automatic Card Creation**: By calling this endpoint, the virtual card is automatically created if the user's Safe account is properly configured. You do not need to call any other endpoint.
-
-
-
-[The virtual card should appear immediately in the card list available with the endpoint](/api-reference/card-management/list-all-cards):
-
-```bash cURL
-curl /api/v1/cards?status_code=1000
-```
-
-The `status_code=1000` query parameter returns only active cards.
-
-
-Card Limits: Users can have a **maximum of 5 active cards including physical and virtual cards combined**. Active cards exclude voided, lost, and stolen cards.
-
diff --git a/cards/pse-integration.mdx b/cards/pse-integration.mdx
deleted file mode 100644
index 5e703f8..0000000
--- a/cards/pse-integration.mdx
+++ /dev/null
@@ -1,220 +0,0 @@
----
-title: Partner Secure Elements (PSE) Integration
-description: Access sensitive Card information from your client application.
----
-
-## Overview
-
-If you want to display sensitive information, such as card numbers, in your front-end, you'll need to interact with our **Partner Secure Elements (PSE)** service. The easiest way to do this is by using the [PSE SDK](https://www.npmjs.com/package/@gnosispay/pse-sdk) from Gnosis Pay.
-
-To initialize the SDK, you'll need an `App ID` provided to you upon registration with Gnosis Pay. You'll also need an **ephemeral-token**. This ephemeral-token can be retrieved with a call to our private PSE API using mTLS authentication.
-
-
- **Backend Only**: An mTLS authentication can only be performed from a
- back-end. For this reason, you need a back-end responsible for retrieving the
- ephemeral-token and sending it to your front-end upon request. We'll go
- through each step in this guide.
-{" "}
-
-Once your front-end has the ephemeral-token, it can initialize the PSE SDK and use it to display secure elements.
-
-Here's a diagram showing each step:
-
-```mermaid
- sequenceDiagram
- participant FE as Your Frontend
- participant BE as Your Backend
- participant API as PSE API
-
- FE->>BE: Get ephemeral-token
- BE->>API: Get ephemeral-token (mTLS Certificates)
- API-->>BE: Receive ephemeral-token
- BE-->>FE: Receive ephemeral-token
-
- Note over FE: Initialize PSE SDK with ephemeral-token and App ID
-
- FE->>API: PSE SDK Requests Card Information
- API-->>FE: Display Card Information Inside an Iframe
-```
-
-Reference implementations are available for a [front-end](https://github.com/gnosispay/ui) and a [back-end](https://github.com/gnosispay/ui/tree/main/pse-backend-demo).
-
----
-
-## Secure Connection Using mTLS Authentication
-
-**Mutual TLS (mTLS)** is a type of authentication in which two parties in a connection authenticate each other using the TLS protocol. Your back-end will establish an mTLS authentication with the Gnosis Pay private PSE API to receive an ephemeral-token.
-
-### How to Generate mTLS Certificates
-
-After signing up through the [Partners Dashboard](https://partners.gnosispay.com/), you will receive an `App ID` instantly, which will be used in the certificate generation below. You must first create a private key and then generate a Certificate Signing Request (CSR) using the `App ID` as follows:
-
-```graphql
-# APP_ID is a string starting with `gp_` that you have received from Gnosis Pay
-export APP_ID="gp_woop_123"
-
-# Create a private key (NEVER share with anyone)
-openssl ecparam -name prime256v1 -genkey -noout -out "${APP_ID}.key.pem"
-
-# Create the CSR (OK to share)
-openssl req -new -sha256 -key "${APP_ID}.key.pem" -out "${APP_ID}.csr.pem" -subj "/CN=${APP_ID}"
-```
-
-You can now share the `${APP_ID}.csr.pem` file with the Gnosis Pay team. **DO NOT EVER** share the `.key.pem` file with **ANYONE**.
-
-Once we receive your Certificate Signing Request, we will sign it and send you back the signed certificates. These signed certificates, along with your private key, are used to establish the connection with the PSE API.
-
-### How to Establish an mTLS Authentication (in Node.js)
-
-You should securely store the certificates in your environment along with your private key.
-
-Your environment should expose the certificates and private key, for example:
-
-```rust
-SIGNED_CERTIFICATES="-----BEGIN CERTIFICATE-----
-ABCQz ....
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-DEFC7 ....
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-GHICc ....
------END CERTIFICATE-----"
-
-PRIVATE_KEY="-----BEGIN EC PRIVATE KEY-----
-ABCD....
------END EC PRIVATE KEY-----"
-```
-
-Here's a Node.js implementation to request the ephemeral-token in two different ways:
-
-
-
-```js Using Axios
-const httpsAgent = new https.Agent({
- cert: process.env.SIGNED_CERTIFICATES,
- key: process.env.PRIVATE_KEY,
- rejectUnauthorized: true, // Ensure SSL verification
-});
-
-const ephemeralTokenRequest = await axios({
- httpsAgent: httpsAgent,
- method: "POST",
- url: `https://api-pse.gnosispay.com/api/v1/ephemeral-token`,
- headers: { "Content-Type": "application/json" },
- // Axios adds the user-agent automatically
-});
-```
-
-```js Using https.request
-import https from "https";
-
-const httpsAgent = new https.Agent({
- cert: CERT,
- key: KEY,
- rejectUnauthorized: true,
-});
-
-const req = https.request(
- {
- hostname: "api-pse.gnosispay.com",
- path: "/api/v1/ephemeral-token",
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "User-Agent": "User-Client/1.0.0",
- },
- agent: httpsAgent,
- },
- (res) => {
- let data = "";
- res.on("data", (chunk) => {
- data += chunk;
- });
-
- res.on("end", () => {
- console.log("Status:", res.statusCode);
-
- try {
- const parsedData = JSON.parse(data);
- console.log("Response:", parsedData);
- } catch {
- console.log("Raw response:", data);
- }
- });
- }
-);
-
-req.on("error", (error) => {
- console.error("Request error:", error);
-});
-req.end();
-```
-
-
-
-Please refer to our [API documentation](/api-reference/endpoints/generate-a-new-ephemeral-token) on the PSE service for more information about the specific endpoint.
-
-
- The ephemeral-token, as its name suggests, is valid for a very short time
- frame. It is advised to generate a new one for every usage of the SDK.
-
-
----
-
-## How to Use the PSE SDK
-
-The PSE SDK will help you display sensitive information. It injects secure iframes into your front-end and exposes callbacks to interact with it. Refer to the [PSE SDK documentation](https://www.npmjs.com/package/@gnosispay/pse-sdk) for instructions and examples.
-
-## How to Customize the Style of Secure Elements in the iframe
-
-For security reasons, the only way to apply custom styling to iframe elements is to prepare and share a **CSS file** with the Gnosis Pay team. This file, named `.css`, will be incorporated into the iframe.
-
-Standard styling is applied to the iframe elements by default. You can override the style of these classes and IDs as needed. Here are some of them:
-
-#### Card Data
-
-- `.pse-container` - A shared class for all iframe containers.
-- `#pse-card-data-container` - The main container for displaying card data.
-- `.pse-card-field` - The container for each card data field (card number, expiry date, security code).
-- `.pse-card-label` - Labels for each field.
-- `.pse-card-value` - The container for the actual card data values.
-
-#### Set PIN Form
-
-- `.pse-container` - A shared class for all iframe containers.
-- `#pse-set-pin-form` - The main form container.
-- `#pse-set-pin-success-container` - The success state container.
-- `.pse-set-pin-container` - The base container class.
-- `.pse-set-pin-button` - The base class for all buttons.
-- `#pse-continue-pin-button` - The continue button.
-- `#pse-done-button` - The done button.
-
----
-
-### Styling Guide
-
-Here is a suggested workflow to customize the styling:
-
-1. In your front-end, load the element you wish to customize (e.g., the card data).
-1. Locate the custom CSS file with your name in either the "**Style Editor**" in Firefox or the "**Sources**" panel on Chrome/Brave. In the example below, the file is `gnosis_pay_ui.css`.
-1. Apply your desired styling. The changes will be reflected in your interface immediately.
-1. Save the file and send it to Gnosis Pay for application in production.
-
-Here is an example of overriding the `.pse-card-field` class in Firefox:
-
-
-## React Native Integration
-
-If you'd like to integrate the PSE SDK into a React Native application, you can use the [React Native PSE SDK](https://www.npmjs.com/package/@gnosispay/pse-react-native) package to help integrating the WebView piece.
-
-However, as the PSE requires hosting on your domain, you will still need to host the PSE Frame on your backend, on your domain.
-
-This frame can be as simple as an HTML page that invokes the PSE JS SDK.
-
-In our reference implementation repository, next to the examples of implementing backend endpoint for ephemeral token generation, you can
-find [an example of such page](https://github.com/gnosispay/ui/blob/main/pse-backend-demo/src/static/native-webview.html) returned by the same backend that generates the ephemeral token.
-
-Note that this page should be responsible for fetching the ephemeral token from your backend, and passing it to the PSE JS SDK.
-
-You will then pass this URL to the React Native WebView component, through the `webViewUrl` prop, together with other parameters that you can find in the [React Native PSE SDK documentation](https://www.npmjs.com/package/@gnosispay/pse-react-native).
diff --git a/changelog/index.mdx b/changelog/index.mdx
new file mode 100644
index 0000000..8310fa6
--- /dev/null
+++ b/changelog/index.mdx
@@ -0,0 +1,9 @@
+---
+title: "Changelog"
+description: "New features, improvements, and fixes for Gnosis Pay"
+---
+
+
+ We're putting the finishing touches on our public API and docs. Changelog
+ entries will start appearing here shortly.
+
diff --git a/concepts/accounts/account-status.mdx b/concepts/accounts/account-status.mdx
new file mode 100644
index 0000000..0691e9b
--- /dev/null
+++ b/concepts/accounts/account-status.mdx
@@ -0,0 +1,17 @@
+---
+title: "Account Status"
+---
+
+An account moves through a small set of statuses over its lifecycle. The table below describes what each status means and what, if anything, is expected from the user or partner while an account is in it.
+
+| Status | What it means
+|---|---|
+| **Provisioning** | The account is being created and its card Safe is being configured. This is a transitional status that should resolve automatically as part of account setup. |
+| **Active** | The account is active and fully operational. The user can fund their account, use their card, and access all account features. |
+| **Blocked** | The account has been blocked and cannot be used. All active cards are restricted and no new cards can be created. Can be blocked by the partner (via Dashboard) or by Gnosis Pay directly. |
+| **Closed** | The account has been permanently closed. |
+
+
+
+ **Closed account** cannot be reopened or reactivated under any circumstances.
+
diff --git a/concepts/accounts/account.mdx b/concepts/accounts/account.mdx
new file mode 100644
index 0000000..e925759
--- /dev/null
+++ b/concepts/accounts/account.mdx
@@ -0,0 +1,41 @@
+---
+title: "Account Overview"
+description: "Understanding what a Gnosis Pay account is and how spending limits work"
+---
+
+A Gnosis Pay account is created once a user has been fully onboarded and has completed KYC.
+
+## Token and Safe configuration
+
+When an account is provisioned, it's configured with the **token** that the account will spend from. This token, along with a linked **Safe**, defines the account's spending source: the Safe is authorized to spend the configured token on behalf of the account.
+
+## Account spending limits
+
+Gnosis Pay accounts support configurable spending limits at two levels:
+
+- **User-configured limits** : users can set their own account limit, giving them direct control over how much they spend, independent of any partner-level configuration.
+- **Partner-configured limits** : as a partner, you can apply a custom limit on an account, up to a maximum limit set for that account type.
+
+
+ These two levels work together: a partner can define the limit for an account based on their program setup with Gnosis Pay, while the user retains control to set a stricter limit within it for their own spending discipline.
+
+
+
+ To apply for a custom limit for your users, [contact sales].
+
+
+## Multi-currency support
+
+A single account can hold and transact in multiple currencies, so users aren't restricted to a single-currency balance.
+
+
+ Multi-currency setup is not enabled by default. To request it for your program with Gnosis Pay, [contact sales].
+
+
+Because Gnosis Pay cards run on the **Visa network**, which accepts merchants worldwide, a purchase can be either a **domestic transaction** (merchant currency matches the account's currency) or an **international transaction** — in which case it becomes an **FX transaction**, converting between the account's currency and the currency the merchant is charging in.
+
+
+ As a partner, you can also customize the **FX fees** applied to these conversions, giving you control over how international spend is priced for your users.
+
+
+To find out which tokens are supported, visit the [Tokens and Chains Supported](/concepts/safe/tokens-and-chains-supported) page.
diff --git a/concepts/architecture.mdx b/concepts/architecture.mdx
new file mode 100644
index 0000000..117879e
--- /dev/null
+++ b/concepts/architecture.mdx
@@ -0,0 +1,65 @@
+---
+title: "Gnosis Pay Architecture"
+description: "How onboarding, spending, and settlement flow through Gnosis Pay"
+---
+
+Gnosis Pay is the orchestration layer that connects KYC flows, self custody of funds through safe account, KYT/AML checks on funds transfer, payment processing, and settlement. The diagram below shows how each system plugs in.
+
+
+
+
+The diagram reads in two directions. From the top down, it shows how a **partner** integrates. From the user's journey through the middle and bottom, it shows what an **end user** experiences.
+
+## For partners
+
+You integrate with Gnosis Pay infrastructure and get assigned a TenantID (also referred as PartnerID, which is an idenitifier for you as a partner) and allows us to spin up dedicated credentials to access userbase.
+
+Partner infrastructure has three components:
+
+
+
+ Onboard your users end-to-end wallet sign-in with SIWE, email and TOS, and KYC. You can drive the full flow through the API or bring your own onboarding. If you have Sumsub instance, you can also perform KYC sharing
+
+
+ Subscribe to real-time events to keep your systems in sync and power notifications to your users.
+
+
+ Manage your program, support your users (B2C), and access analytics and user data — so you own the relationship directly.
+
+
+ A partner-hosted secure element for displaying sensitive card details (PAN, CVV, expiry) on your own domain. Authenticated with mTLS.
+
+
+
+
+Gnosis Pay as the orchestration layer exposes three domains:
+
+- **Account** : create and manage user accounts, balances, and limits.
+- **Card**: issue and control virtual cards, card limits and control.
+- **Processing + Settlement**: authorization, transaction processing, and settlement across the payment rails. We also handle chargebacks and disputes.
+
+
+## For users
+
+From the end user's point of view, the platform moves them from sign-in to spending in a single continuous flow.
+
+
+
+ The user connects their wallet with SIWE (Sign-In with Ethereum), verifies their email, and accepts the terms of service.
+
+
+ The user completes KYC through Sumsub. Once verified and approved, their KYC is to be linked with user account.
+
+
+ Gnosis Pay provisions the user's account with Pismo and deploys their **Spending Safe** — a self-custodial Safe where the user's funds are held. A card is issued against the account. During this deployment, we also set the user's spendable currency and primary token that is allowed to be spent from user's safe.
+
+
+ The user deposits funds into their Spending Safe. Every deposit is screened by **KYT** (AML) before the funds become spendable.Because the Spending Safe is self-custodial, the user keeps control of their funds throughout deposits, balances, and withdrawals.
+
+
+ When the user pays with their card, the transaction is authorized in real time against the account balance and balance is moved accordingly on ledger.
+
+
+ Spending is settled through Monavate on a 12-hour batch.
+
+
diff --git a/concepts/auth/token.mdx b/concepts/auth/token.mdx
new file mode 100644
index 0000000..42cb764
--- /dev/null
+++ b/concepts/auth/token.mdx
@@ -0,0 +1,54 @@
+---
+title: "Authentication & Token Management"
+description: "Understanding SIWE auth, and how access/refresh tokens work"
+---
+
+Gnosis Pay authenticates users through **Sign-In with Ethereum (SIWE)** following EIP 4361 in which it verifies a **cryptographic signature** produced by the user's wallet proving control of the address.
+
+Once that signature is verified, the API issues a pair of tokens (**access** and **refresh**) that represent the authenticated session going forward. This page explains the reasoning behind both pieces: why SIWE, and how the token system keeps a session secure without asking the user to sign a message on every request.
+
+## Sign in with Ethereum
+
+SIWE (formalized as **EIP-4361**) defines a standard, human-readable message format that a wallet signs to prove address ownership.
+
+- **Signed message:** The signed message itself states *who* is authenticating, *for which domain*, at *what time*, and often includes a random nonce. The user can visually inspect what they're agreeing to before signing, rather than blindly approving an opaque hash.
+- **Domain-bound:** Because the message includes the requesting domain, a signature obtained on `app.example.com` can't be silently replayed against Gnosis Pay's own domain by a malicious site — this is what domain whitelisting on our side enforces.
+- **Replay resistance:** The nonce and timestamp in the message mean a captured signature can't be reused indefinitely to mint new sessions.
+
+
+## Session Management against Auth token
+
+A signature proves identity for a single moment — it doesn't create an ongoing session by itself. So once SIWE verification succeeds, Gnosis Pay issues two tokens that stand in for "this address is authenticated" over time:
+
+| | Access Token | Refresh Token |
+|---|---|---|
+| **Lifespan** | 15 minutes | 7 days |
+| **Format** | Stateless JWT | Opaque random string |
+| **Role** | Proves the session on each request | Used only to mint a new access token |
+| **Where it should live** | Memory / short-lived storage | Secure, encrypted storage |
+
+## Why tokens rotate
+
+Every time a refresh token is used, it's invalidated and replaced with a new one this is **token rotation**. The old refresh token becomes permanently unusable the moment a new one is issued, even if it hasn't expired yet.
+
+This turns refresh tokens into a kind of tripwire: in normal operation, only one "version" of a session's refresh token is ever valid at a time. If a refresh token is ever used *twice*, once by the legitimate client, once by an attacker who copied it the system can detect that the token has already been consumed and end the session for everyone holding a copy.
+
+```mermaid
+sequenceDiagram
+ participant Wallet
+ participant Gnosis Pay
+
+ Wallet->>Gnosis Pay: Sign SIWE message (EIP-4361)
+ Gnosis Pay->>Wallet: Verify signature → issue Access + Refresh Token
+
+ Note over Wallet,Gnosis Pay: Access Token proves the session (15 min)
+
+ Note over Wallet,Gnosis Pay: Access Token expires
+
+ Wallet->>Gnosis Pay: Present Refresh Token
+ Gnosis Pay->>Wallet: Invalidate old Refresh Token → issue new Access + Refresh Token
+```
+
+
+ For the actual request/response and endpoints to implement this flow, see the [Authentication Guide](/guides/auth-with-siwe).
+
diff --git a/concepts/card/decline-codes.mdx b/concepts/card/decline-codes.mdx
new file mode 100644
index 0000000..1206a72
--- /dev/null
+++ b/concepts/card/decline-codes.mdx
@@ -0,0 +1,283 @@
+---
+title: "Card Decline Reasons"
+description: "Every card decline code, the customer-facing message shown, and its technical cause"
+---
+
+When a card transaction is declined, Gnosis Pay returns a decline code and a customer-facing message via the Partner API, webhooks, and on the Partner Dashboard. The 90+ underlying technical codes from Pismo are grouped into customer-facing categories, so cardholders see clear, actionable language rather than a raw processor code.
+
+This page lists every code by category, the message shown to the user, and the technical reason behind it — useful when investigating a specific decline with your support team.
+
+
+ A code not listed here falls back to a generic message: *"Transaction denied (code: `{code}`)"*.
+
+
+## 1. Temporary issue
+
+**Message shown to user:** *"Temporary issue. Please try again."*
+
+Transient, infrastructure-level failures. Retrying the transaction typically resolves them.
+
+| Code | Technical Reason |
+|---|---|
+| `91` | Authorization system or issuer system inoperative |
+| `998` | Card hash not present in database |
+| `ACE` | Network transactions API communication error |
+| `ACT` | Account timeout |
+| `AEE` | Anti-fraud external generic error |
+| `AET` | Anti-fraud external API timeout |
+| `AFE` | Anti-fraud internal API generic error |
+| `AGE` | Account generic error |
+| `AIT` | Anti-fraud internal API timeout |
+| `ANF` | Acceptance not found |
+| `AUD` | Authorization disabled |
+| `BCE` | Balance config generic error |
+| `BCT` | Balance config timeout |
+| `BII` | Balance inquiry internal error |
+| `CET` | Card timeout |
+| `CGE` | Card generic error |
+| `CLF` | Credit limit impact not found |
+| `CMD` | Card mode disabled |
+| `CNU` | Account status unknown |
+| `CTT` | Card token timeout |
+| `CV3` | CVC3 not configured |
+| `DCE` | Distributor API communication error |
+| `ETR` | Exceed time to reversal |
+| `FR3` | IAV validation failed |
+| `FR7` | Card not present in database |
+| `HCE` | HSM communication error |
+| `IMA` | Invalid message authentication code |
+| `IMF` | Invalid message format |
+| `IZA` | Zero amount not allowed |
+| `LAE` | Unexpected error fetching account information |
+| `LCT` | Ledger account timeout |
+| `LNF` | Account not found |
+| `LUD` | Limit update duplicated ID error |
+| `LUE` | Error updating ledger |
+| `LUT` | Ledger timeout |
+| `OOT` | Orgs operation timeout |
+| `OP1` | Generic error or system failure |
+| `PAE` | Unexpected error fetching parameters |
+| `PAT` | Timeout fetching parameters |
+| `PCT` | Timeout in processing code definition |
+| `PGE` | Program config generic error |
+| `PRE` | Unexpected error fetching program |
+| `PRT` | Timeout fetching program |
+| `RAD` | Rates API denial |
+| `RAE` | Error on authorization amount calculation |
+| `STD` | Denied by second authorizer |
+| `TGE` | Card token generic error |
+| `ZBA` | Zero balance API unauthorized |
+| `ZBE` | Zero balance API general error |
+| `ZBF` | Zero balance client webhook forbidden |
+| `ZBP` | Partial authorization response invalid in zero balance purchases |
+| `ZBT` | Zero balance API timeout |
+| `ZBU` | Zero balance client webhook unavailable |
+
+## 2. Card could not be read
+
+**Message shown to user:** *"Card could not be read. Please try again."*
+
+| Code | Technical Reason |
+|---|---|
+| `FAT` | ATC validation failed |
+| `FRE` | Cryptogram data validation failed |
+| `FRH` | POS entry mode validation failed |
+| `FRN` | Chip field validation failed |
+| `FRO` | Chip signature validation failed |
+
+## 3. Card status invalid
+
+**Message shown to user:** *"Card status invalid. Contact support."*
+
+| Code | Technical Reason |
+|---|---|
+| `BNI` | Card is inoperative |
+| `BNW` | Card has warning status |
+| `CSU` | Card status unknown |
+
+## 4. Card transaction limit reached
+
+**Message shown to user:** *"Card transaction limit reached."*
+
+| Code | Technical Reason |
+|---|---|
+| `CTE` | Transaction counter exceeded |
+
+## 5. Mismatched key value for DCC
+
+**Message shown to user:** *"Mismatched key value for DCC"*
+
+| Code | Technical Reason |
+|---|---|
+| `DIC` | Invalid country for DCC definition |
+| `DIY` | Invalid currency for DCC definition |
+
+## 6. Card not activated
+
+**Message shown to user:** *"Card not activated. Please activate."*
+
+| Code | Technical Reason |
+|---|---|
+| `FRB` | Card is in created status (not activated) |
+
+## 7. Card no longer valid
+
+**Message shown to user:** *"Card no longer valid."*
+
+| Code | Technical Reason |
+|---|---|
+| `VED` | Card is deleted |
+
+##8. Mismatched key value for refund
+
+**Message shown to user:** *"Mismatched key value for Refund."*
+
+| Code | Technical Reason |
+|---|---|
+| `DCM` | Original authorization not found at refund |
+
+## 9. Currency conversion not permitted
+
+**Message shown to user:** *"Currency conversion not permitted. Select local currency."*
+
+| Code | Technical Reason |
+|---|---|
+| `DCC` | DCC transaction not allowed for program |
+
+## 10. Security check failed
+
+**Message shown to user:** *"Security check failed. Please try again."*
+
+| Code | Technical Reason |
+|---|---|
+| `CAV` | CAVV 3DS validation failed |
+
+## 11. Payment declined, contact support
+
+**Message shown to user:** *"Payment declined. Contact support."*
+
+| Code | Technical Reason |
+|---|---|
+| `MPC` | Program config not found |
+| `PRN` | Program not found |
+| `ZBD` | Zero balance client declined |
+
+## 12. Wallet payment failed, re-add card
+
+**Message shown to user:** *"Wallet payment failed. Re-add card and try again."*
+
+| Code | Technical Reason |
+|---|---|
+| `TNP` | Token not provided |
+| `Z26` | Card token not found |
+| `Z29` | Card token failed |
+| `Z30` | Token does not match card |
+
+## 13. Payment failed, check token status
+
+**Message shown to user:** *"Payment failed. Please check your token status."*
+
+| Code | Technical Reason |
+|---|---|
+| `Z22` | *(pending confirmation)* |
+
+## 14. Use PIN to complete transaction
+
+**Message shown to user:** *"Use PIN to complete transaction"*
+
+| Code | Technical Reason |
+|---|---|
+| `PNP` | *(pending confirmation)* |
+
+## 15. Invalid currency
+
+**Message shown to user:** *"Invalid currency. Contact support."*
+
+| Code | Technical Reason |
+|---|---|
+| `PIC` | *(pending confirmation)* |
+
+## 16. Transaction type not supported
+
+**Message shown to user:** *"Transaction type not supported. Please try again."*
+
+| Code | Technical Reason |
+|---|---|
+| `OON` | *(pending confirmation)* |
+
+## 17. Verification not completed
+
+**Message shown to user:** *"Verification not completed. Please try again."*
+
+| Code | Technical Reason |
+|---|---|
+| `NCV` | Entry mode not allowed with no-CVM |
+
+## 18. DCC not allowed
+
+**Message shown to user:** *"DCC not allowed"*
+
+| Code | Technical Reason |
+|---|---|
+| `MDC` | Multi-currency not allowed for DCC authorization |
+
+## 19. Installment not allowed
+
+**Message shown to user:** *"Installment not allowed"*
+
+| Code | Technical Reason |
+|---|---|
+| `ISE` | Insufficient statements |
+
+## 20. Mismatched account type
+
+**Message shown to user:** *"Mismatched Account type for this transaction"*
+
+| Code | Technical Reason |
+|---|---|
+| `IAT` | Invalid account type |
+
+## 21. Card type not supported
+
+**Message shown to user:** *"Card type not supported"*
+
+| Code | Technical Reason |
+|---|---|
+| `GCD` | Gift card denial |
+
+## 22. Payment method not accepted here
+
+**Message shown to user:** *"Payment method not accepted here."*
+
+| Code | Technical Reason |
+|---|---|
+| `FR5` | Magnetic stripe not allowed in this country |
+
+## 23. Other decline codes
+
+These codes fall outside the standard grouping (business, fraud, or card-status declines) and are shown with their own descriptive message directly.
+
+| Code | Message |
+|---|---|
+| `810` | Insufficient balance |
+| `CED` | Incorrect Exp Date, please check and retry |
+| `CNC` | Account cancelled |
+| `CND` | Account blocked |
+| `FL6` | Card blocked by anti-fraud |
+| `FR1` | CVV1 or CVC1 validation failed |
+| `FR2` | Incorrect CVV/CVC, please check and retry |
+| `FR6` | Password validation failed |
+| `PFT` | Do not honor |
+| `RED` | Operation not allowed. Contact support |
+| `TSM` | Password tries exceeded |
+| `UBN` | NFC disabled |
+| `VEV` | Expired virtual card |
+| `VNM` | Card expired |
+| `BND` | Card is cancelled |
+| `BNF` | Card flagged for fraud |
+| `BNM` | Card is damaged |
+| `BNP` | Card reported lost |
+| `BNR` | Card reported stolen |
+| `BNU` | Card is unreceived |
+| `CPE` | Card is in pending status |
+| `UBT` | Card is blocked |
diff --git a/concepts/card/overview.mdx b/concepts/card/overview.mdx
new file mode 100644
index 0000000..e6260e9
--- /dev/null
+++ b/concepts/card/overview.mdx
@@ -0,0 +1,39 @@
+---
+title: "Card Overview"
+description: "Understanding Gnosis Pay virtual cards, provisioning, and spending limits"
+---
+
+Gnosis Pay issues **virtual cards** that can be added to Apple Pay and Google Pay, letting users spend directly from their account without a physical card.
+
+## Card provisioning
+
+By default, each partner program is configured to issue **one virtual card per user**. This can be increased if a partner needs multiple cards per user — that's a configuration decided with the Gnosis Pay team during integration, not something set per-user at runtime.
+
+
+ If your program needs more than one card per user, this needs to be configured during integration. Contact our integration team to discuss.
+
+
+## Adding a card to a mobile wallet
+
+Once issued, a virtual card can be added to following with help of push provisioning:
+
+- **Apple Pay**
+- **Google Pay**
+
+This lets the user tap to pay with their phone or watch, without needing a physical card.
+
+## Card limit vs. account limit
+
+There are two distinct limits that govern how much a user can spend, and it's important not to conflate them:
+
+| | Card Limit | Account Limit |
+|---|---|---|
+| **What it governs** | Spending through a specific card | The account's total spendable balance |
+| **Default** | — | $10,000 |
+| **Who can configure it** | — | User (can set their own, stricter limit) or partner (can apply a custom limit up to the account's maximum) |
+
+The **account limit** is effectively a cap on spendable balance: by default this is set to **$10,000**, though a user can choose to set a *lower* limit on their own account and card for their own spending discipline
+
+
+ See [Account Overview](/concepts/accounts/account#account-spending-limits) for how account-level and partner-level limits interact.
+
diff --git a/concepts/card/transaction-enrichment.mdx b/concepts/card/transaction-enrichment.mdx
new file mode 100644
index 0000000..6ff17f4
--- /dev/null
+++ b/concepts/card/transaction-enrichment.mdx
@@ -0,0 +1,40 @@
+---
+title: "Transaction Enrichment"
+description: "How raw card transactions get enriched with merchant name, logo, and location data"
+---
+
+When a card transaction is authorized, the data that arrives from the card network is minimal and often cryptic, a raw merchant descriptor, an MCC code, sometimes a truncated or misspelled merchant name.
+
+**Transaction enrichment** is the process of matching that raw transaction data against a merchant database to attach richer, human-readable context such as the merchant's real name, logo, category, and location so partners can build a transaction history that actually looks like something a user recognizes, rather than a raw statement line.
+
+## Why this matters for the user experience
+
+Without enrichment, a transaction might show up as something like, when a user visits the transaction history:
+
+`SQ *COFFEE SHOP LLC 4155551234 CA`
+
+
+With enrichment, the same transaction can be shown as:
+
+- A recognizable **merchant name** ("Blue Bottle Coffee")
+- The merchant's **logo**
+- A **shop category** (e.g., "Coffee Shop") instead of a raw MCC code
+- The merchant's **location** including address, or map coordinates
+
+This is what lets partners build a transaction feed similar to what users expect from neobanks, rather than exposing raw network data.
+
+## How it works, conceptually
+
+When a transaction is authorized, Gnosis Pay attempts to match the raw merchant data against the service provider used for fetching the merchant database. This match either succeeds, partially succeeds, or fails — which is why enrichment carries a **status** alongside the merchant and shop data.
+
+## What gets enriched
+
+Broadly, enrichment can surface:
+
+- **Merchant identity**: name and logo
+- **Shop details**: category, tags, and merchant type
+- **Location**: street address, city, country, and map coordinates (where available)
+
+
+ Enrichment is applied automatically; there's nothing partners need to configure to receive enriched fields on a transaction.
+
diff --git a/concepts/intro.mdx b/concepts/intro.mdx
new file mode 100644
index 0000000..a806a7b
--- /dev/null
+++ b/concepts/intro.mdx
@@ -0,0 +1,42 @@
+---
+title: "Introduction to Gnosis Pay"
+description: "Stablecoin card-as-a-service infrastructure for wallets, neobanks, exchanges, and payment processors"
+---
+
+Gnosis Pay is a B2B stablecoin card program manager that enables fintech products like neobanks, wallets, etc to launch cards to users. Gnosis Pay Partners can run their own branded card programs and own their user relationships, while our platform handles the complexity of card network integrations, settlement flows, compliance, and payment processing.
+
+Partners can go further and customize their integration to fully own the end-to-end experience bringing their own KYC and user onboarding flows, or using the Gnosis Pay APIs directly to onboard users and issue cards.
+
+Gnosis Pay APIs are designed with developer experience who are integrating this in product. Developement team gets access to a dedicated sandbox environment, where they can test Visa transactions through the fully integrated Pismo Simulator, and run KYC flows.
+
+
+This documentation covers the guides for the product, alongside the full API reference.
+
+
+## Built for teams turning crypto into everyday finance
+
+
+
+ Turn DeFi into a daily financial hub with branded cards, auto-yield deposits, and real-world payments.
+
+
+ Expand into new markets with one integration, offering local payment rails like SEPA, Pix, and Faster Payments — without needing local banking infrastructure.
+
+
+ With one API, exchanges enable users to spend USDC or EURC directly from their accounts via instant virtual cards that support retention and enhance utility.
+
+
+ Launch white-labeled card issuing with ease using your existing KYC/AML flow, in a fully branded experience.
+
+
+
+## What's next
+
+
+
+ Learn the core concepts and building blocks behind Gnosis Pay.
+
+
+ Explore endpoints to integrate cards, KYC, and payments.
+
+
diff --git a/concepts/kyc/kyc-overview.mdx b/concepts/kyc/kyc-overview.mdx
new file mode 100644
index 0000000..32b9870
--- /dev/null
+++ b/concepts/kyc/kyc-overview.mdx
@@ -0,0 +1,36 @@
+---
+title: "KYC Overview"
+description: "How identity verification works on Gnosis Pay, and what to expect during the process"
+---
+
+Before a user can be onboarded to Gnosis Pay, they must complete **Know Your Customer (KYC)** verification. This is a regulatory requirement for financial services — it confirms the user is who they say they are, checks eligibility (e.g., country of residence, age, sanctions/watchlist screening), and helps prevent fraud and financial crime on the platform.
+
+## We use Sumsub
+
+Gnosis Pay partners with **Sumsub** to handle identity verification. Sumsub collects and analyzes the user's identity documents (such as POA) and, depending on the flow, a liveness check to confirm the document belongs to the person submitting it.
+
+As a partner integrating Gnosis Pay, you don't build identity verification yourself — you embed the Sumsub iframe, and Gnosis Pay receives the verification result and status updates from Sumsub on your behalf.
+
+
+Gnosis Pay allows acceptance of sharing KYC of user from partner instance to Gnosis Pay instance and vice versa within SumsSub. To understand the flow, read [KYC Sharing (Sumsub Flow)](/integration_guides/kyc-sharing-sumsub-flow) guide to integrate this flow into your application.
+
+
+## KYC statuses
+
+As a user moves through verification, their KYC application passes through a series of statuses — from initial document collection, through automated and (where needed) manual review, to a final outcome.
+
+
+ See the full [KYC Statuses](/concepts/kyc/kyc-statuses) reference for what each status means, what the user experiences, and suggested user-facing messaging for each.
+
+
+## Country eligibility
+
+Not all countries of residence are eligible for registration. Eligibility depends on regulatory coverage and Gnosis Pay's supported jurisdictions.
+
+
+ See [countries of residence eligible for registration](https://kb.gnosispay.com/articles/7878909911-mandatory-info-countries-of-residence-eligible-for-registration) for the current list.
+
+
+## What's next
+
+Once KYC is approved, the user is moved to next onboarding state which is account provisioning and deploying a new safe on behalf of user.
diff --git a/concepts/kyc/kyc-statuses.mdx b/concepts/kyc/kyc-statuses.mdx
new file mode 100644
index 0000000..ec2fd3d
--- /dev/null
+++ b/concepts/kyc/kyc-statuses.mdx
@@ -0,0 +1,17 @@
+---
+title: "KYC Statuses"
+description: "Every status a user's KYC application can be in, what it means, and how to communicate it"
+---
+
+As a user moves through identity verification, Sumsub reports a status for their KYC application. The table below summarizes each status; details, suggested messaging, and escalation guidance follow.
+
+| Status | Action Required | What it means |
+|---|---|---|
+| **Documents Requested** | Yes | Sumsub is requesting documents from the user. Appears at the start of KYC and any time additional documentation is needed (e.g. Proof of Identity, Proof of Address). KYC cannot progress until documents are submitted. |
+| **Pending** | No | The user has submitted documents and Sumsub is performing automated analysis. Normal transitional status; most users move through it quickly. |
+| **Approved** | No | KYC verification is complete and the user is eligible to proceed to the next onboarding stage. Does not mean the account is fully active. |
+| **Resubmission Requested** | Yes | The submission was reviewed and resubmission is required. Common causes: expired documents, poor image quality, name mismatches, unsupported document types. |
+| **Requires Action** | Dependent on Gnosis Pay team | The application is queued for manual review by the compliance team. Common for higher-risk scores or when additional data is needed. Typically resolves within 24 hours (up to 3–5 business days). |
+| **Rejected** | Final status | The application has been permanently rejected. Cannot be resubmitted by the user or reversed by the partner; only Gnosis Pay can manually review a possible error. |
+
+---
diff --git a/concepts/safe/overview.mdx b/concepts/safe/overview.mdx
new file mode 100644
index 0000000..4c75d7d
--- /dev/null
+++ b/concepts/safe/overview.mdx
@@ -0,0 +1,53 @@
+---
+title: "GP Safe Account"
+description: "Understanding Gnosis Pay Safe account architecture and modules"
+---
+
+Gnosis Pay's on-chain infrastructure is built on top of the Safe protocol, providing a secure and programmable foundation for digital payments. Each user receives a unique Safe account that acts as their on-chain wallet, with additional modules that enable spending limits, time delays, and delegated spending capabilities.
+
+## Architecture Overview
+
+The Gnosis Pay Safe consists of a core Safe account with three main modules:
+
+- **Core Safe Account**: The base Safe wallet that holds funds and processes transactions
+- **Delay Module**: Controls transaction timing and provides security delays
+- **Roles Module**: Manages spending permissions and allowance limits
+
+
+### Instant Withdrawals
+Withdrawals from the Gnosis Pay Safe reduce the spendable balance immediately to avoid double spending and then sync with the on-chain balance. During this process, the card is not blocked from operations.
+
+### Multi-Currency Support
+The Roles module now supports multi-token configurations so that users can spend different currencies via their spending safe.
+
+## Module Configurations:
+
+### Delay Module Settings
+- **Transaction delay**: 25 hours
+- **Transaction expiration**: 31 hours
+
+
+These extended timeouts are designed to discourage direct delay module interaction. Failed transactions require the full expiration period before they can be skipped.
+
+
+### Daily onchain spending limits
+
+The Roles module enforces a hardcoded on-chain limit of **\$20K per token***, twice the card limit. This buffer exists because card clearing and settlement can take 1–4 days after a transaction, and the higher on-chain limit ensures uninterrupted card operations over that window without requiring any additional user signatures.
+
+
+
+ Any interaction with the delay module will block the card and require customer support intervention to resolve the issue.
+
+
+
+
+## Account balances state breakdown for authenticated user
+
+Gnosis Pay provides detailed balance breakdowns to give users complete visibility into their fund status. The authenticated user's account displays four distinct balance types:
+
+| Balance Type | Description | Increases When | Decreases When |
+|--------------|-------------|----------------|----------------|
+| **Spendable** | Amount available for immediate spending via card transactions or withdrawals | • Deposits clear AML analysis • Refunds are processed • Returns of goods are credited | • Card transactions are authorized • Withdrawals are initiated |
+| **Non-Spendable** | Funds that cannot be used for spending. Flagged for review or potential return | • Dependent on AML checks | • Funds are returned to source • Funds are manually released after review |
+| **Processing Deposits** | Incoming deposits currently undergoing AML analysis. Not yet available for spending | • New deposit is received | • AML analysis completes (moves to spendable or non-spendable) |
+| **Processing Withdrawals** | Outgoing withdrawals currently being processed. Deducted from spendable but not yet settled on-chain | • Withdrawal is initiated | • Withdrawal settles on-chain |
diff --git a/concepts/safe/tokens-and-chains-supported.mdx b/concepts/safe/tokens-and-chains-supported.mdx
new file mode 100644
index 0000000..17298c1
--- /dev/null
+++ b/concepts/safe/tokens-and-chains-supported.mdx
@@ -0,0 +1,25 @@
+---
+title: "Tokens and Chains Supported"
+description: "Supported chains and the tokens available for Gnosis Pay accounts on each"
+---
+
+Gnosis Pay accounts can be provisioned with tokens across the following chains.
+
+## Celo
+
+| Token | Contract Address |
+|---|---|
+| USDC | `0xceba9300f2b948710d2653dd7b07f33a8b32118c` |
+| USDT | `0x48065fbbe25f71c9282ddf5e1cd6d6a887483d5e` |
+
+## Gnosis Chain
+
+| Token | Contract Address |
+|---|---|
+| EURe | `0xcB444e90D8198415266c6a2724b7900fb12FC56E` |
+| GBPe | `0x5Cb9073902F2035222B9749F8fB0c9BFe5527108` |
+| USDCe | `0x2a22f9c3b484c3629090FeED35F17Ff8F88f76F0` |
+
+
+ [Contact sales] to support custom chain or custom token for your integration.
+
diff --git a/concepts/whybuild.mdx b/concepts/whybuild.mdx
new file mode 100644
index 0000000..764bd38
--- /dev/null
+++ b/concepts/whybuild.mdx
@@ -0,0 +1,78 @@
+---
+title: "Why Build with Gnosis Pay"
+description: "What you get as a partner from user onboading to launching a full fledged card program"
+---
+Gnosis Pay gives you the infrastructure to launch a card program and the flexibility to run it your way. Here's what that means in practice, for your business and for your engineering team.
+
+## For your business
+
+### Onboarding
+
+
+ Already onboard your users with Sumsub? Integrate that flow directly and share KYC into Gnosis Pay. Your users complete verification once, no duplicate KYC to get a card.
+
+
+### Multi-chain and multi-currency
+
+
+
+ Launch your card program on the chains you choose. We support the underlying infrastructure across multiple chains. Gnosis Pay infra is live on Celo and Gnosis Chain.
+
+
+ Enable your ecosystem's stablecoin as a spending currency, fully on-chain with native support. A single card can hold and spend multiple tokens.
+
+
+ Multi-currency cards (e.g. EUR, USD, GBP) can be enabled for your program if you want to offer it to users, subject to pricing.
+
+
+
+### Money movement
+
+
+
+ Fully self-custodial. Withdraw your balance instantly — no lock-up periods, no settlement delays.
+
+
+ Reversals are processed the moment we receive the message from the network. Funds return to the user's balance immediately, with no manual step in between.
+
+
+
+### Fees Customization
+
+
+
+ Design your own cards to match your brand (subject to Visa's approval timeline).
+
+
+ Add your own markup on top of transactions.
+
+
+ Set account- and card-level spending limits per user.
+
+
+ Shape the program to your product from onboarding to card controls.
+
+
+
+### Payments experience
+
+
+ Provision cards to Apple Pay and Google Pay so users can tap to pay from day one.
+
+
+## For developers and product teams
+
+
+
+ Configure webhooks and PSE setup, and access analytics and user data so your team can own communications and user relationships directly.
+
+
+ A full sandbox to build and test against before going to production, including transaction simulations.
+
+
+ Subscribe to real-time events to power user notifications and keep your systems in sync.
+
+
+ Technical integration support available throughout your build.
+
+
diff --git a/docs.json b/docs.json
index 607aaff..b1293aa 100644
--- a/docs.json
+++ b/docs.json
@@ -1,106 +1,140 @@
{
+ "$schema": "https://mintlify.com/docs.json",
"theme": "mint",
- "name": "Gnosis Pay Documentation",
+ "name": "Gnosis Pay",
"colors": {
- "primary": "#707A2D",
- "light": "#D8EB81",
- "dark": "#919E3A"
+ "primary": "#766DE5",
+ "light": "#9994ED",
+ "dark": "#1A1751"
+ },
+ "appearance": {
+ "default": "light",
+ "strict": false
+ },
+ "logo": {
+ "light": "/static/img/logo-dark.svg",
+ "dark": "/static/img/logo-light.svg"
+ },
+ "navbar": {
+ "links": [
+ {
+ "label": "Contact Sales team",
+ "href": "https://form.typeform.com/to/naN3irHW?typeform-source=gnosispay.com"
+ }
+ ],
+ "primary": {
+ "type": "button",
+ "label": "Sign up as Partner",
+ "href": "https://partner-dashboard.sandbox.gnosispay.com/auth/signin"
+ }
},
- "favicon": "/static/img/favicon.ico",
"navigation": {
"tabs": [
{
- "tab": "Guides",
+ "tab": "Concepts",
"groups": [
{
- "group": "Introduction to Gnosis Pay",
- "icon": "play",
- "pages": ["index", "integration-model", "auth", "onboarding-flow"]
+ "group": "Welcome to Gnosis Pay",
+ "pages": [
+ "concepts/intro",
+ "concepts/whybuild",
+ "concepts/architecture"
+ ]
+ },
+ {
+ "group": "Authentication",
+ "pages": ["concepts/auth/token"]
+ },
+ {
+ "group": "KYC",
+ "pages": ["concepts/kyc/kyc-overview", "concepts/kyc/kyc-statuses"]
},
{
"group": "Accounts",
- "icon": "user",
"pages": [
- "account",
- "account/update-authenticated-account",
- "account/adding-safe-owner"
+ "concepts/accounts/account",
+ "concepts/accounts/account-status"
]
},
{
- "group": "On/Off Ramps",
- "icon": "landmark",
+ "group": "Safe & Modules",
"pages": [
- "on-off-ramps/index",
- "on-off-ramps/iban-integration",
- "on-off-ramps/kyc-sharing"
+ "concepts/safe/overview",
+ "concepts/safe/tokens-and-chains-supported"
]
},
{
"group": "Cards",
- "icon": "credit-card",
"pages": [
- "cards/concepts",
- "cards/create-physical-cards",
- "cards/create-virtual-cards",
- "cards/card-order-state-transitions",
- "cards/pse-integration"
+ "concepts/card/overview",
+ "concepts/card/decline-codes",
+ "concepts/card/transaction-enrichment"
]
+ }
+ ]
+ },
+ {
+ "tab": "Integration Guide",
+ "groups": [
+ {
+ "group": "Getting started",
+ "pages": ["guides/configuring-environment"]
},
{
- "group": "Card Transactions",
- "icon": "receipt",
+ "group": "Authentication & Onboarding",
+ "pages": ["guides/auth-with-siwe", "guides/onboarding"]
+ },
+ {
+ "group": "KYC Sharing",
"pages": [
- "transactions/index",
- "transactions/lifecycle",
- "transactions/integration-guide"
+ "guides/kyc-sharing/pass-kyc",
+ "guides/kyc-sharing/monerium"
]
},
{
- "group": "On-chain",
- "icon": "cubes",
+ "group": "Manage Accounts",
"pages": [
- "gp-onchain/overview",
- "gp-onchain/about-GP-safe",
- "gp-onchain/sign-message",
- "gp-onchain/daily-limit",
- "gp-onchain/withdraw-funds-from-safe",
- "gp-onchain/third-party-bridges"
+ "guides/accounts/manage-accounts",
+ "guides/accounts/limits",
+ "guides/accounts/account-statement",
+ "guides/accounts/onchain-withdrawal"
]
},
{
- "group": "Webhooks",
- "icon": "webhook",
+ "group": "Manage Cards",
"pages": [
- "webhooks/introduction",
- "webhooks/getting-started",
- "webhooks/events"
+ "guides/cards/create-virtual",
+ "guides/cards/card-limit",
+ "guides/cards/card-simulator"
]
- }
- ]
- },
- {
- "tab": "API reference",
- "groups": [
- {
- "group": "Authentication",
- "pages": ["api-reference/intro", "api-reference/auth-app"]
},
{
- "group": "API reference",
- "openapi": "https://api.gnosispay.com/api-docs/spec.json"
+ "group": "Secure Card Elements via PSE",
+ "pages": ["guides/pse/pse", "guides/pse/pse-integration"]
},
{
- "group": "PSE API",
- "openapi": "https://api-pse-public.gnosispay.com/api-docs/spec.json"
+ "group": "Webhooks",
+ "pages": [
+ "guides/webhooks/webhook",
+ "guides/webhooks/webhook-events"
+ ]
}
]
+ },
+ {
+ "tab": "API Reference",
+ "openapi": "https://core.prod.gnosispay.com/user-api/openapi.json"
+ },
+ {
+ "tab": "Migration",
+ "pages": ["migration/migration-overview"]
+ },
+ {
+ "tab": "Changelog",
+ "pages": ["changelog/index"]
}
]
},
- "logo": {
- "light": "/static/img/Logo-black.svg",
- "dark": "/static/img/Logo-white.svg"
- },
"contextual": {
"options": [
"copy",
diff --git a/gp-onchain/about-GP-safe.mdx b/gp-onchain/about-GP-safe.mdx
deleted file mode 100644
index de4ffb7..0000000
--- a/gp-onchain/about-GP-safe.mdx
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: About GP Safe
-description: Gnosis Pay's on-chain infrastructure is built on top of the [Safe protocol](https://safe.global), providing a secure and programmable foundation for digital payments. Each user gets a unique Safe account that acts as their on-chain wallet, with additional modules that enable spending limits, time delays, and delegated spending capabilities.
----
-
-The Gnosis Pay Safe consists of a core Safe account with three main modules attached:
-
-1. **Core Safe Account**: The base Safe that holds funds and manages ownership
-2. **Delay Module**: Controls transaction timing and provides security delays
-3. **Roles Module**: Manages spending permissions and allowance limits
-4. **Bouncer Module**: Handles account access validation and security
-
-### Gnosis Pay Safe Setup Process
-
-To understand how a Gnosis Pay Safe differs from a standard Safe, let's examine the [account setup flow](https://github.com/gnosispay/account-kit/blob/main/src/entrypoints/accounts-actions/accountSetup.ts#L88) that transforms a basic 1/1 Safe into a fully configured Gnosis Pay Safe Account:
-
-
-
-- **Ownership Transfer**: Swaps the Safe owner to an inaccessible address (`0x0000000000000000000000000000000000000002`)
-- **Module Enablement**: Enables both the Roles and Delay modules on the Safe
-
-
-
-- **Deployment**: Creates a new Delay module instance for the account
-- **Cooldown Configuration**: Sets the transaction delay period (typically 3 minutes)
-- **Expiration Setting**: Configures how long queued transactions remain valid
-- **Owner Access**: Grants the initial Safe owner (the owner before the ownership transfer) access to the delay module
-
-
-
-- **Deployment**: Creates a new Roles module instance for the account
-- **Allowance Configuration**: Sets up spending limits with:
- - Initial balance amount
- - Maximum balance cap
- - Refill amount per period
- - Time period for refills
-- **Role Assignment**: Grants spending permissions to designated spender addresses
-- **Target Scoping**: Restricts spending to specific token contracts
-- **Function Scoping**: Limits operations to ERC20 transfer functions only
-- **Ownership Transfer**: Transfers control to the Bouncer module
-
-
-
-- **Deployment**: Creates the final security layer
-- **Access Control**: Manages who can interact with the account
-
-
-
-### Spending Control Flow
-
-The spending process follows this pattern:
-
-1. **Spender Request**: A designated spender requests a transaction
-2. **Allowance Check**: The Roles module verifies spending limits
-3. **Delay Enforcement**: If limits allow, the transaction enters the delay queue
-4. **Time Delay**: The transaction waits for the configured cooldown period
-5. **Execution**: After the delay, the transaction can be executed
-6. **Balance Update**: The allowance balance is updated accordingly
diff --git a/gp-onchain/daily-limit.mdx b/gp-onchain/daily-limit.mdx
deleted file mode 100644
index 6dc9ebf..0000000
--- a/gp-onchain/daily-limit.mdx
+++ /dev/null
@@ -1,174 +0,0 @@
----
-title: "Change GP Safe daily spending limit"
-description: "Manage daily spending limits for Gnosis Pay Safe accounts"
----
-
-The daily spending limit feature allows partners to manage daily spending limits for Gnosis Pay Safe accounts.
-
-All transactions are gasless, enabling users to perform these operations completely free of charge.
-
-## Overview
-
-The daily spending limit update process involves the following steps:
-
-1. **Fetch EIP-712 Typed Data** - Get the EIP-712 typed data for wallet signing
-2. **Sign and Submit** - Sign the EIP-712 data and submit the update
-3. **Monitor Update** - Wait for the delay relay to process the change and check the new limit
-
-
-- The signing wallet must be one of the Gnosis Pay Safe signers (EOA or smart contract wallet)
-- For smart contract wallets, signatures are verified using ERC-1271 standard
-- Updates are processed after a 3-minute delay as transactions are going through the Gnosis Pay delay relay
-
-
-## Daily Limit Update Process
-
-
-
-
-[Get the EIP-712 typed data that needs to be signed by the user's wallet](/api-reference/account-management/get-eip-712-typed-data-for-setting-daily-limit):
-
-```bash cURL
-curl -X GET \
- /api/v1/accounts/daily-limit/transaction-data?newLimit=${newLimit}
-```
-
-The response contains EIP-712 typed data with `domain`, `types`, `primaryType`, and `message` fields that need to be signed by the user's wallet using the EIP-712 standard.
-
-
-
-
-**Safe Activation Required**: This step only works when the Gnosis Pay Safe account has been fully activated and its modules are deployed. If you receive an error during submission, ensure that the Safe account activation process has been completed first.
-
-For more information about Safe account setup and module deployment, see the [Safe Management API documentation](/api-reference/safe-management/deploy-and-setup-a-safe).
-
-
-The EIP-712 typed data from Step 1 must be signed by the user's wallet using the EIP-712 signature standard.
-
-
-**Wallet Requirements:**
-- The wallet must be a signer of the Gnosis Pay Safe account
-- For **EOA wallets**: Standard EIP-712 signature is used
-- For **smart contract wallets**: ERC-1271 signature verification is used, and you must include the `smartWalletAddress` field in the request body
-
-
-Once signed, [submit the transaction to update the daily limit](/api-reference/account-management/set-new-daily-spending-limit):
-
-
-```bash cURL
-# For EOA wallets
-curl -X PUT /api/v1/accounts/daily-limit \
- -d '{
- "newLimit": 1500,
- "signature": "0x...",
- "message": {
- "salt": "0x...",
- "data": "0x..."
- }
-}'
-
-# For smart contract wallets (include smartWalletAddress)
-curl -X PUT /api/v1/accounts/daily-limit \
- -d '{
- "newLimit": 1500,
- "signature": "0x...",
- "message": {
- "salt": "0x...",
- "data": "0x..."
- },
- "smartWalletAddress": "0x..."
-}'
-```
-
-
-
-
-The daily limit change is processed through a delay relay mechanism that executes after 3 minutes.
-
-You can monitor the transaction status using the [delay-relay monitoring endpoint](/api-reference/safe-management/list-delayed-transactions)
-or by checking your Safe's transaction history.
-
-Additionally, you can also [poll the following endpoint to check when the new limit becomes active](/api-reference/account-management/get-current-daily-spending-limit):
-
-
-```bash cURL
-curl -X GET /api/v1/accounts/daily-limit
-```
-
-
-
-
-## Complete Implementation Example
-
-The following example demonstrates the complete flow:
-
-```typescript
-
-const newDailyLimit = 1337;
-
-/**
- * Step 1: Fetch EIP-712 typed data for signing
- */
-const response = await fetch(
- `https://api.gnosispay.com/api/v1/accounts/daily-limit/transaction-data?newLimit=${newDailyLimit}`
-);
-const { data: typedData } = await response.json();
-
-/**
- * Step 2: Sign the EIP-712 typed data
- */
-const signature = await walletClient.signTypedData({
- ...typedData,
- domain: {
- ...typedData.domain,
- verifyingContract: typedData.domain.verifyingContract as `0x${string}`,
- },
-});
-
-/**
- * Step 3: Submit the signed data
- */
-const submitResponse = await fetch("https://api.gnosispay.com/api/v1/accounts/daily-limit", {
- method: "PUT",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- newLimit: newDailyLimit,
- signature,
- message: typedData.message,
- // Include smartWalletAddress if using a smart contract wallet
- // smartWalletAddress: "0x...",
- }),
-});
-
-const { data: updateResult } = await submitResponse.json();
-
-/**
- * Step 4: Monitor for the updated limit
- */
-console.log(`Daily limit update submitted with ID: ${updateResult.id}`);
-console.log(`Status: ${updateResult.status}`);
-console.log("Limit change will be processed after the 3-minute delay period");
-
-// Optional: Poll for the updated limit
-const pollForUpdate = async () => {
- const checkResponse = await fetch(
- "https://api.gnosispay.com/api/v1/accounts/daily-limit"
- );
- const { data: { dailyLimit: updatedLimit } } = await checkResponse.json();
-
- if (updatedLimit === newDailyLimit) {
- console.log(`Limit successfully updated to: ${updatedLimit}`);
- return true;
- }
-
- console.log(`Waiting for update... Current: ${updatedLimit}, Target: ${newDailyLimit}`);
- return false;
-};
-
-// Poll every 30 seconds until the update is complete
-const interval = setInterval(async () => {
- if (await pollForUpdate()) {
- clearInterval(interval);
- }
-}, 30000);
-```
diff --git a/gp-onchain/overview.mdx b/gp-onchain/overview.mdx
deleted file mode 100644
index 978fb0c..0000000
--- a/gp-onchain/overview.mdx
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Overview
-description: Understanding the on-chain integration options for Gnosis Pay, including the Account Kit SDK and direct contract integration approaches.
----
-
-## Account Kit
-
-We provide the Account Kit as a way to accelerate on-chain integration for the TypeScript/JavaScript ecosystem. This SDK abstracts away the complexity of our multi-module Safe architecture, making it easier for developers to integrate with Gnosis Pay's on-chain infrastructure directly.
-
-Installing instructions and comprehensive examples are available in the [Account Kit repository](https://github.com/gnosispay/account-kit). The SDK is open source and actively maintained by the Gnosis Pay team.
-
-All examples in this section of the documentation assume you are using the Account Kit SDK.
-
-## Direct Integration without Account Kit
-
-For other programming languages, you can use their own cryptocurrency libraries (e.g., go-ethereum for Go, web3.py for Python, and so on) and integrate directly with the contracts. However, this approach requires additional steps since the Account Kit relies on TypeScript/JavaScript projects from Gnosis such as `@gnosis.pm/safe-contracts`, `@gnosis.pm/zodiac`, and related dependencies.
-
-Integrating directly means you'll need to explore the Account Kit source code and its dependencies to understand:
-- **Contract Function Calls**: Which specific functions are being called on the Safe, Delay, Roles, and Bouncer modules
-- **Payload Encoding**: How transaction data is encoded and structured for each operation
-- **Module Interactions**: The sequence and coordination between different modules
-- **Parameter Validation**: What parameters are required and how they're validated
-
-This reverse-engineering approach is entirely doable for teams with strong smart contract integration experience, but it requires significant additional development time compared to using the Account Kit directly.
\ No newline at end of file
diff --git a/gp-onchain/sign-message.mdx b/gp-onchain/sign-message.mdx
deleted file mode 100644
index f88d8a0..0000000
--- a/gp-onchain/sign-message.mdx
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: Sign Messages with GP Safe
-description: Learn how to sign messages using your GP Safe account with the delay module for enhanced security.
----
-
-Unlike traditional EOA (Externally Owned Account) message signing, GP Safe message signing goes through the delay module.
-
-
-Message signing with GP Safe requires the account to be fully configured with the delay module enabled. If you haven't set up your Safe account yet, see the [Safe Account Configuration](/onboarding-flow#4-safe-account-configuration) section first.
-
-
-## Message Signing Process
-
-GP Safe message signing follows the same two-phase pattern as other delayed operations:
-
-1. **Enqueue Phase**: Submit the message signing request to the delay queue
-2. **Dispatch Phase**: Execute the message signing after the delay period expires
-
-[You can find a complete working example here.](https://github.com/gnosispay/account-kit/blob/main/examples/src/sign-safe-message/index.ts)
-
-
-
-First, prepare the message you want to sign.
-
-This can be any string, such as:
-
-```typescript
-const message = "Hello, this is a message to be signed by my GP Safe!";
-```
-
-Or structured data that needs to be signed by your GP Safe account.
-
-
-
-
-Use the `populateSignMessageEnqueue` function to create a transaction that submits your message signing request to the delay queue.
-
-```typescript
-import { populateSignMessageEnqueue } from "@gnosispay/account-kit";
-
-const owner: Signer = {}; // Your wallet signer
-const account = "0x..."; // Your GP Safe address
-const chainId = 100; // Gnosis Chain
-
-const enqueueTx = await populateSignMessageEnqueue(
- { account, chainId },
- message,
- // EIP-712 signature callback
- ({ domain, primaryType, types, message }) =>
- owner.signTypedData(domain, primaryType, types, message)
-);
-
-// Send the enqueueTx using your wallet
-```
-
-
-This transaction will be queued in the delay module and cannot be executed immediately. The delay period (typically 3 minutes) must pass before the message can be signed.
-
-
-
-
-The message signing request is now in the delay queue. You must wait for the configured cooldown period to expire before proceeding.
-
-
-The default delay period is 3 minutes (180 seconds). This provides time for you to review and potentially cancel the operation if needed.
-
-
-You can check the delay queue status using the `accountQuery` function from `@gnosispay/account-kit`.
-
-
-
-
-Once the delay period has expired, use the `populateSignMessageDispatch` function to execute the queued message signing operation.
-
-```typescript
-import { populateSignMessageDispatch } from "@gnosispay/account-kit";
-
-const dispatchTx = populateSignMessageDispatch(
- { account },
- message
-);
-
-// Send the dispatchTx using your wallet
-```
-
-
-Unlike the enqueue transaction, the dispatch transaction doesn't require a signature since it's executing a previously authorized operation.
-
-
-
-
-
diff --git a/gp-onchain/third-party-bridges.mdx b/gp-onchain/third-party-bridges.mdx
deleted file mode 100644
index 4b6f45e..0000000
--- a/gp-onchain/third-party-bridges.mdx
+++ /dev/null
@@ -1,56 +0,0 @@
----
-title: "Third-Party Bridges"
----
-Gnosis Pay partners can select and integrate bridge aggregators based on their specific infrastructure requirements and target chain support. The following recommended solutions ensure optimal cross-chain functionality for end users.
-
-
-### Recommended Bridge Aggregators
-
-
-
-
- Intent-based bridging with deep liquidity for Gnosis Chain, supporting EURe and GBPe. Converts Bitcoin and non-EVM assets to Gnosis Chain in a single transaction.
-
-
-
- Cross-chain bridge aggregator offering best-price, auto-routed swaps across multiple blockchains.
-
-
-
- Cross-chain liquidity aggregation protocol enabling seamless token transfers across multiple chains and bridges.
-
-
-
- Native Gnosis Chain protocol offering MEV-protected, gasless bridging from Ethereum.
-
-
-
- Handles complex cross-chain routes like Solana USDC → Gnosis with custom message passing.
-
-
-
diff --git a/gp-onchain/withdraw-funds-from-safe.mdx b/gp-onchain/withdraw-funds-from-safe.mdx
deleted file mode 100644
index e14b640..0000000
--- a/gp-onchain/withdraw-funds-from-safe.mdx
+++ /dev/null
@@ -1,162 +0,0 @@
----
-title: "Withdraw funds from GP Safe"
-description: "How to send funds from the Gnosis Pay Safe to your EOA or somewhere else."
----
-
-The withdrawal feature allows partners to withdraw tokens from Gnosis Pay Safe accounts to any external address **on the Gnosis Chain**.
-All transactions are gasless, enabling users to perform these operations completely free of charge.
-
-The withdrawal process involves the following steps:
-
-1. **Fetch Transaction Data** - Get the EIP-712 typed data for signing
-2. **Sign and Submit** - Sign the transaction and submit the withdrawal
-3. **Monitor Execution** - Wait for the delay relay to process the withdrawal
-
-
-Please remember the following:
-- The signing wallet must be one of the Gnosis Pay Safe signers (EOA or smart contract wallet)
-- For smart contract wallets, signatures are verified using ERC-1271 standard
-- Withdrawals are processed after a 3-minute delay as transactions are going through the Gnosis Pay delay relay
-- Cards are temporarily frozen for 3 minutes during withdrawal processing as a security measure
-
-
-## Withdrawal Process
-
-
-
-
-Get the EIP-712 typed data that needs to be signed by the user's wallet [(spec)](/api-reference/account-management/retrieve-transaction-data-for-withdrawing-from-safe):
-
-```bash cURL
-curl -X GET \
-/api/v1/accounts/withdraw/transaction-data?tokenAddress=${tokenAddress}&to=${toAddress}&amount=${amount}
-```
-
-The response contains EIP-712 typed data that needs to be signed by the user's wallet.
-
-
-
-The EIP-712 typed data from Step 1 must be signed by the user's wallet using the EIP-712 signature standard.
-
-
-**Wallet Requirements:**
-- The wallet must be a signer of the Gnosis Pay Safe account
-- For **EOA wallets**: Standard EIP-712 signature is used
-- For **smart contract wallets**: ERC-1271 signature verification is used, and you must include the `smartWalletAddress` field in the request body
-
-
-
-
-Once signed, [submit the transaction to execute the withdrawal](/api-reference/account-management/withdraw-from-safe-with-signature):
-
-```bash cURL
-# For EOA wallets
-curl -X POST \
-/api/v1/accounts/withdraw \
--H "Content-Type: application/json" \
--d '{
- "tokenAddress": "0x123456....",
- "to": "0x78910...",
- "amount": "1000000000000000000",
- "signature": "0x1234567890abcdef...",
- "message": {
- "salt": "0x1234567890...abcdef",
- "data": "0x123456...00de0b6b3a7640000"
- }
-}'
-
-# For smart contract wallets (include smartWalletAddress)
-curl -X POST \
-/api/v1/accounts/withdraw \
--H "Content-Type: application/json" \
--d '{
- "tokenAddress": "0x123456....",
- "to": "0x78910...",
- "amount": "1000000000000000000",
- "signature": "0x1234567890abcdef...",
- "message": {
- "salt": "0x1234567890...abcdef",
- "data": "0x123456...00de0b6b3a7640000"
- },
- "smartWalletAddress": "0x..."
-}'
-```
-
-
-
-
-The withdrawal is processed through a **delay relay mechanism** that executes after 3 minutes.
-
-You can monitor the transaction status using the [delay-relay monitoring endpoints](/api-reference/safe-management/list-delayed-transactions) or by checking your Safe's transaction history.
-
-
-
-
-
-
-## Complete Implementation Example
-
-The following example demonstrates the complete flow:
-
-```typescript
-const tokenAddress = "0x..."; // Token contract address
-const toAddress = "0x..."; // Destination address
-const amount = "1000000000000000000"; // Amount in token base units
-
-/**
- * Step 1: Fetch transaction data for signing
- */
-const response = await fetch(
- `https://api.gnosispay.com/api/v1/accounts/withdraw/transaction-data?tokenAddress=${tokenAddress}&to=${toAddress}&amount=${amount}`
-);
-const { data: typedData } = await response.json();
-
-/**
- * Step 2: Sign and submit the transaction
- */
-const signature = await walletClient.signTypedData({
- ...typedData,
- domain: {
- ...typedData.domain,
- verifyingContract: typedData.domain.verifyingContract as `0x${string}`,
- },
-});
-
-const submitResponse = await fetch("https://api.gnosispay.com/api/v1/accounts/withdraw", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- tokenAddress,
- to: toAddress,
- amount,
- signature,
- message: typedData.message,
- // Include smartWalletAddress if using a smart contract wallet
- // smartWalletAddress: "0x...",
- }),
-});
-
-const { data: transactionResult } = await submitResponse.json();
-
-/**
- * Step 3: Monitor execution (optional)
- */
-console.log(`Withdrawal submitted with ID: ${transactionResult.id}`);
-console.log(`Status: ${transactionResult.status}`);
-console.log("Transaction will be processed after the 3-minute delay period");
-```
-
-
-## Security Considerations
-
-- Make sure the user is aware this transfer is on the Gnosis Chain
-- Remember that transactions cannot be reversed once executed
-- Cards are temporarily frozen during the withdrawal process as a security measure
-
-## Token Support
-
-This feature supports withdrawing any ERC-20 token that exists in the Safe account. Make sure to:
-
-- Use the correct token contract address
-- Specify the amount in the token's base units (considering decimals)
-- Ensure sufficient token balance in the Safe account
diff --git a/guides/accounts/account-statement.mdx b/guides/accounts/account-statement.mdx
new file mode 100644
index 0000000..3adabbc
--- /dev/null
+++ b/guides/accounts/account-statement.mdx
@@ -0,0 +1,57 @@
+---
+title: "Account Statements"
+description: "Retrieve account statements for users"
+---
+
+## Retrieve Account Statement
+
+An account statement is a chronological record of all financial activity associated with a user's account. It provides a transparent view of money moving in and out of the account over a selected period of time, giving users complete visibility into their account activity.
+
+To retrieve the account statement, use the [`GET /user/statement`](/api-reference/user-movements/get-account-statement) endpoint.
+
+
+
+```bash
+curl --request GET \
+ --url "https://core.sandbox.gnosispay.in/user-api/user/statement?limit=&cursor=&startDate=&endDate="
+```
+
+
+```bash
+curl --request GET \
+ --url "https://core.prod.gnosispay.com/user-api/user/statement?limit=&cursor=&startDate=&endDate="
+```
+
+
+
+### Query Parameters
+
+
+ Maximum number of statement entries to return per page.
+
+
+
+ Pagination cursor for retrieving the next page of results.
+
+
+
+ ISO-8601 date to filter statement entries from (inclusive).
+
+
+
+ ISO-8601 date to filter statement entries up to (inclusive).
+
+
+## Types of Account Statement Entries
+
+Each entry in an account statement falls into one of three transaction types, each with its own set of possible statuses:
+
+| Transaction Type | Possible Statuses |
+|------------------|-------------------|
+| **Card Transactions** | `pending`, `settled`, `cancelled`, `declined` |
+| **Deposits** | `pending`, `approved`, `rejected` |
+| **Withdrawals** | `pending`, `processing`, `completed`, `failed` |
+
+
+ A declined card transaction still appears on the statement with status `declined` — see [Card Decline Reasons](/concepts/card/decline-codes) for why a transaction may be declined.
+
diff --git a/guides/accounts/limits.mdx b/guides/accounts/limits.mdx
new file mode 100644
index 0000000..2db7998
--- /dev/null
+++ b/guides/accounts/limits.mdx
@@ -0,0 +1,75 @@
+---
+title: "Account Daily Spending Limit"
+description: "Get and set the daily spending limit for the authenticated user's account"
+---
+
+
+ See [Account Overview](/concepts/accounts/account#account-spending-limits) for how user-configured and partner-configured limits interact conceptually.
+
+
+
+By default, an account's daily spending limit is `$10,000`. Users can lower this limit for their own account, but it cannot be set above $10,000 unless agreed with the partner during onboarding.
+
+
+ This is a **cumulative daily spending limit shared across all cards on the account**, not a per-card cap. If an account has multiple cards, the combined spend across all of them together is capped at the configured limit. It is also not a per-transaction cap: an authorization that meets or exceeds the remaining limit can still be approved, after which subsequent eligible authorizations for the rest of the day are declined.
+
+
+
+## Get Account Daily Spending Limit
+
+Returns the daily spending limit configured on the authenticated user's account.
+
+`amount` is expressed in the currency's smallest unit — for USD this means cents (e.g. `1000` = $10.00, `1000000` = $10,000.00). `syncStatus` indicates whether the most recently requested update has been fully applied.
+
+
+
+```bash
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/user/account/limit \
+ --header 'Authorization: Bearer '
+```
+
+
+```bash
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/user/account/limit \
+ --header 'Authorization: Bearer '
+```
+
+
+
+
+## Set Account Daily Spending Limit
+
+Sets the daily spending limit for the authenticated user's account.
+
+`amount` is in the currency's smallest unit — for USD that means cents, so to set a $10.00 limit send `1000`, and the maximum allowed value `1000000` corresponds to $10,000.00. Must be in the range `(0, 1,000,000]`. **Only USD is currently accepted.**
+
+The response returns the new limit immediately with `syncStatus: "pending"`, transitioning to `"synced"` once the change has been applied downstream.
+
+
+
+```bash
+curl --request PUT \
+ --url https://core.sandbox.gnosispay.in/user-api/user/account/limit \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "amount": 500000,
+ "currency": "USD"
+ }'
+```
+
+
+```bash
+curl --request PUT \
+ --url https://core.prod.gnosispay.com/user-api/user/account/limit \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "amount": 500000,
+ "currency": "USD"
+ }'
+```
+
+
diff --git a/guides/accounts/manage-accounts.mdx b/guides/accounts/manage-accounts.mdx
new file mode 100644
index 0000000..5a59f58
--- /dev/null
+++ b/guides/accounts/manage-accounts.mdx
@@ -0,0 +1,63 @@
+---
+title: "Manage Accounts"
+description: "Retrieve account details and balance information for the authenticated user"
+---
+
+
+ New to how accounts work on Gnosis Pay? Read [Account Overview](/concepts/accounts/account) first — it covers the concepts behind account balances, spending limits, and multi-currency support. This guide covers the API calls to retrieve that data.
+
+
+## Account details for authenticated user
+
+To get authenticated user account details, call [`GET /user/account`](/api-reference/user-account/get-account).
+
+
+
+```bash
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/user/account
+```
+
+
+```bash
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/user/account
+```
+
+
+
+This will return configuration of the user's account, including chain name, configured currencies, Safe owner address, etc.
+
+## Account balances for authenticated user
+
+Account balances endpoint provides detailed balance breakdowns to give users complete visibility into their fund status. The authenticated user's account displays four distinct balance types:
+
+| Balance Type | Description | Increases When | Decreases When |
+|--------------|-------------|----------------|----------------|
+| **Spendable** | Amount available for immediate spending via card transactions or withdrawals | • Deposits clear AML analysis • Refunds are processed • Returns of goods are credited | • Card transactions are authorized • Withdrawals are initiated |
+| **Non-Spendable** | Funds that cannot be used for spending. Flagged for review or potential return | • Dependent on AML checks | • Funds are returned to source • Funds are manually released after review |
+| **Processing Deposits** | Incoming deposits currently undergoing AML analysis. Not yet available for spending | • New deposit is received | • AML analysis completes (moves to spendable or non-spendable) |
+| **Processing Withdrawals** | Outgoing withdrawals currently being processed. Deducted from spendable but not yet settled on-chain | • Withdrawal is initiated | • Withdrawal settles on-chain |
+
+### Get Account Balances
+
+To request the account balance of the user, call [`GET /user/balances/v2`](/api-reference/user-movements/get-account-balances-v2).
+
+
+
+```bash
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/user/balances/v2
+```
+
+
+```bash
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/user/balances/v2
+```
+
+
+
+
+ Each currency maintains its own separate balance states. For example, USDC and USDT will each have their own spendable, non-spendable, processing deposits, and processing withdrawals amounts.
+
diff --git a/guides/accounts/onchain-withdrawal.mdx b/guides/accounts/onchain-withdrawal.mdx
new file mode 100644
index 0000000..88325a3
--- /dev/null
+++ b/guides/accounts/onchain-withdrawal.mdx
@@ -0,0 +1,60 @@
+---
+title: "Onchain Instant Withdrawals"
+description: "Create request to withdraw funds onchain to wallet address"
+---
+
+## Create Withdrawal Request
+
+The [`POST /user/withdrawals`](/api-reference/user-movements/create-withdrawal) endpoint allows you to create a withdrawal request for a user.
+
+The withdrawal happens to the GP Safe's owner wallet address.
+
+
+ **Withdrawals are per token.** Each withdrawal request targets a single token via `tokenAddress`.
+
+
+
+ **Withdrawal Restrictions:**
+ - Only specific tokens are currently supported for withdrawals.
+ - Withdrawals are restricted to the Safe owner address, the wallet address that initiated the Safe deployment via the [`POST /user/account`](/api-reference/user-account/create-account) endpoint.
+
+
+
+ **Token addresses supported for withdrawals:**
+
+ **Celo**
+ - CeloUSDT = `0x48065fbbe25f71c9282ddf5e1cd6d6a887483d5e`
+ - CeloUSDC = `0xceba9300f2b948710d2653dd7b07f33a8b32118c`
+
+ **Gnosis Chain**
+ - EURe = `0xcB444e90D8198415266c6a2724b7900fb12FC56E`
+ - GBPe = `0x5Cb9073902F2035222B9749F8fB0c9BFe5527108`
+ - USDCe = `0x2a22f9c3b484c3629090FeED35F17Ff8F88f76F0`
+
+ See [Tokens and Chains Supported](/concepts/safe/tokens-and-chains-supported) for the full reference.
+
+
+
+
+```bash
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/user/withdrawals \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "tokenAddress": "",
+ "amount": ""
+ }'
+```
+
+
+```bash
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/user/withdrawals \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "tokenAddress": "",
+ "amount": ""
+ }'
+```
+
+
diff --git a/guides/auth-with-siwe.mdx b/guides/auth-with-siwe.mdx
new file mode 100644
index 0000000..bdee717
--- /dev/null
+++ b/guides/auth-with-siwe.mdx
@@ -0,0 +1,156 @@
+---
+title: "Authenticating with SIWE"
+description: "Implement the SIWE-based authentication flow: retrieving, using, and rotating access and refresh tokens"
+---
+
+
+ To know how authentication and token rotation works in Gnosis Pay, read [Authentication & Tokens guide](/concepts/auth/token). This guide covers the implementation steps.
+
+
+## Authentication Flow
+
+Let's take a look at how to complete SIWE validation and retrieve access tokens.
+
+
+
+ Request the message that users need to Sign in with Ethereum (SIWE) by calling the endpoint with the wallet address in the path and required query parameters.
+
+
+ **Domain Whitelisting Required**: We validate domains on our end for security. Your SIWE message must originate from a domain that has been pre-approved and whitelisted in our system. Contact our team to whitelist your domain before implementing authentication.
+
+
+ See full specification: [GET /auth/siwe/{address}](/api-reference/auth/get-siwe-message)
+
+
+
+```bash
+# these values require prior partner registration (self signup)
+export APP_DOMAIN="myapp.xyz"
+export APP_URI="https://myapp.xyz"
+export APP_NAME="MyCardApp"
+
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/auth/siwe/{address}?domain=$APP_DOMAIN&uri=$APP_URI&appName=$APP_NAME
+```
+
+
+```bash
+# these values require prior partner registration (provisioned by Gnosis team)
+export APP_DOMAIN="myapp.xyz"
+export APP_URI="https://myapp.xyz"
+export APP_NAME="MyCardApp"
+
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/auth/siwe/{address}?domain=$APP_DOMAIN&uri=$APP_URI&appName=$APP_NAME
+```
+
+
+
+
+
+ Submit the signed SIWE message to verify authentication and receive your token pair. Send the wallet address, signature from the user's wallet, and the original SIWE message to get both access and refresh tokens.
+
+ See full specification: [POST /auth/siwe](/api-reference/auth/get-access-token)
+
+
+
+```bash
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/auth/siwe \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "address": "",
+ "signature": "",
+ "message": ""
+ }'
+```
+
+
+```bash
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/auth/siwe \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "address": "",
+ "signature": "",
+ "message": ""
+ }'
+```
+
+
+
+
+ **Secure Storage Required**: Store the refresh token securely to prevent XSS attacks. While our system has mechanisms to invalidate sessions if tokens are compromised, developers must implement proper security measures and secure storage APIs to protect against client-side vulnerabilities.
+
+
+
+
+ Exchange a valid refresh token for a new access token and rotated refresh token. This should be called automatically when your access token expires (every 15 minutes) or when you receive a 401 response.
+
+ See full specification: [POST /auth/refresh](/api-reference/auth/refresh-access-token)
+
+
+
+```bash
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/auth/refresh \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "refreshToken": "your_refresh_token_here"
+ }'
+```
+
+
+```bash
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/auth/refresh \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "refreshToken": "your_refresh_token_here"
+ }'
+```
+
+
+
+
+ **Token Rotation**: Each refresh request invalidates the previous refresh token and issues a new one. Always store the new refresh token from the response for subsequent refresh requests.
+
+
+
+ The refresh token should only be used once. If a refresh token is used twice, the user will be automatically logged out. Preventing race conditions is essential to maintain session integrity.
+
+
+
+
+### Revoking access tokens
+
+To securely log out a user, revoke their current session by invalidating all refresh tokens in the token family.
+
+
+ After successful logout, remove the refresh token from your client's secure storage to complete the logout process.
+
+
+See full specification: [POST /auth/logout](/api-reference/auth/logout)
+
+
+
+```bash
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/auth/logout \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "refreshToken": "your_refresh_token_here"
+ }'
+```
+
+
+```bash
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/auth/logout \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "refreshToken": "your_refresh_token_here"
+ }'
+```
+
+
diff --git a/guides/cards/card-limit.mdx b/guides/cards/card-limit.mdx
new file mode 100644
index 0000000..6ce45db
--- /dev/null
+++ b/guides/cards/card-limit.mdx
@@ -0,0 +1,70 @@
+---
+title: "Card Daily Spending Limit"
+description: "Get and set the daily spending limit for a specific card"
+---
+
+
+
+ **Why this matters for users:** a user with multiple cards may want to limit how much a specific card can spend. For example, capping a card shared with a family member, or a card used only for subscriptions, without changing the overall account limit that governs their other cards. This gives users finer-grained control over their own spending habits.
+
+
+
+ A card's limit only takes effect if it's set **lower** than the [account's daily spending limit](guides/accounts/limits), the account limit is always the hard ceiling, regardless of any card-level limit.
+
+
+## Set Card Daily Spending Limit
+
+Sets the daily spending limit for a card.
+
+`amount` is expressed in the currency's smallest unit, for USD this means cents (e.g. `1000` = `$10.00`, `1000000` = `$10,000.00`). The card must belong to the authenticated user.
+
+The response returns the new limit immediately with `syncStatus: "pending"`, transitioning to `"synced"` once the change has been applied downstream.
+
+
+
+```bash
+curl --request PUT \
+ --url https://core.sandbox.gnosispay.in/user-api/cards/{cardId}/limit \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "amount": 500000,
+ "currency": "USD"
+ }'
+```
+
+
+```bash
+curl --request PUT \
+ --url https://core.prod.gnosispay.com/user-api/cards/{cardId}/limit \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "amount": 500000,
+ "currency": "USD"
+ }'
+```
+
+
+
+
+## Get Card Daily Spending Limit
+
+Returns the daily spending limit configured on a card.
+
+
+
+```bash
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/cards/{cardId}/limit \
+ --header 'Authorization: Bearer '
+```
+
+
+```bash
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/cards/{cardId}/limit \
+ --header 'Authorization: Bearer '
+```
+
+
diff --git a/guides/cards/card-simulator.mdx b/guides/cards/card-simulator.mdx
new file mode 100644
index 0000000..b4039e6
--- /dev/null
+++ b/guides/cards/card-simulator.mdx
@@ -0,0 +1,310 @@
+---
+title: "Simulate Card Transactions"
+description: "Simulate card transactions for testing purposes as part of the sandbox environment"
+---
+
+
+ New to the sandbox environment? Read [Sandbox vs Production](/guides/configuring-environment) to understand more about sandbox environment.
+
+
+## Card Transaction Simulator
+
+The Card Transaction Simulator allows you to test full card transaction lifecycles in the sandbox environment, without sending transactions to the live card network.
+
+When you send a transaction request:
+
+1. The simulator authenticates the request
+2. It checks available balance
+3. It applies lifecycle logic:
+ - **Authorization** creates a hold
+ - **Reversal** releases a hold
+ - **Replacement** adjusts an existing hold
+ - **Clearing** confirms/settles a transaction
+ - **Clearing Cancellation** cancels via clearing
+4. It returns an approval or denial response with production-like fields
+
+```
+https://core.sandbox.gnosispay.in/docs/simulator-api
+```
+
+
+## How to Simulate a Card Transaction
+
+
+
+ Use HTTP Basic Auth:
+ - **Username:** `simulator`
+ - **Password:** Provided during onboarding
+
+ All simulator endpoints require authentication.
+
+
+
+ You can simulate transactions using:
+ - `card_id` → `POST /transactions/simulate`
+ - `pan` → `POST /transactions/simulate-by-pan`
+
+ Both endpoints behave identically.
+
+
+
+ All simulation requests use these fields:
+
+ | Field | Type | Required | Description |
+ |---|---|---|---|
+ | `transaction_type` | string | Yes | `authorization`, `reversal`, `replacement`, `clearing`, or `clearing_cancellation` |
+ | `card_id` | uuid | Yes* | Card UUID (use `pan` instead on the by-PAN endpoint) |
+ | `pan` | string | Yes* | Card PAN (only on the by-PAN endpoint) |
+ | `amount` | string | Yes | Amount in major units (e.g., `"100.50"`) |
+ | `currency` | string | Yes | `USD`, `EUR`, or `GBP` |
+ | `authorization_code` | string | Conditional | Required for `reversal`, `replacement`, `clearing`, and `clearing_cancellation` |
+ | `replacement_amount` | string | Conditional | Required for `replacement` |
+ | `merchant_name` | string | No | Defaults to `"TEST MERCHANT"` |
+ | `merchant_code` | string | No | MCC code. Defaults to `"5541"` |
+
+
+
+## Transaction Types
+
+The simulator supports five transaction types that form a complete lifecycle: **authorization**, **reversal**, **replacement**, **clearing**, and **clearing cancellation**.
+
+### Simulate an Authorization
+
+Authorization creates an initial hold on the card balance.
+
+
+
+```json
+{
+ "transaction_type": "authorization",
+ "card_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "amount": "100.50",
+ "currency": "USD"
+}
+```
+
+ **Required:** `transaction_type`, `amount`, `currency`, and `card_id` or `pan`.
+
+
+
+ The simulator will:
+ - Confirm the card exists
+ - Verify the card is active
+ - Check sufficient available balance
+ - Place a hold for the requested amount
+
+
+
+ If approved, the response includes `authorization_code` and `authorization_id`.
+
+
+ **Save the `authorization_code`** as it's required for reversals, replacements, and clearing operations.
+
+
+
+
+### Simulate a Reversal
+
+Reversal cancels a previous authorization entirely and releases the held amount.
+
+
+
+ You must use the `authorization_code` returned from the original authorization.
+
+
+
+```json
+{
+ "transaction_type": "reversal",
+ "card_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "amount": "100.50",
+ "currency": "USD",
+ "authorization_code": "ABC123"
+}
+```
+
+
+
+ The simulator will:
+ - Validate the original authorization exists
+ - Confirm the amount matches
+ - Release the full held balance
+
+
+
+### Simulate a Replacement
+
+Replacement adjusts a previous authorization to a different amount.
+
+
+
+ Use the `authorization_code` from the original authorization.
+
+
+
+```json
+{
+ "transaction_type": "replacement",
+ "card_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "amount": "100.50",
+ "currency": "USD",
+ "authorization_code": "ABC123",
+ "replacement_amount": "75.00"
+}
+```
+
+ **Required:** `authorization_code` and `replacement_amount`.
+
+
+
+ The simulator will:
+ - Validate the original authorization
+ - Reduce or increase the held amount
+ - Update the balance accordingly
+
+
+
+### Simulate a Clearing
+
+Clearing confirms a previous authorization (settlement/Base II) and finalizes the transaction.
+
+
+
+ Use the `authorization_code` from the original authorization.
+
+
+
+```json
+{
+ "transaction_type": "clearing",
+ "card_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "amount": "100.50",
+ "currency": "USD",
+ "authorization_code": "ABC123"
+}
+```
+
+
+
+ The simulator will:
+ - Validate the original authorization
+ - Process the settlement
+ - Finalize the transaction
+
+
+ The simulator requires a minimum 2-minute gap between clearing messages for the same authorization. Sending a second clearing before this window elapses will result in a `409` error.
+
+
+
+
+### Simulate a Clearing Cancellation
+
+Clearing cancellation cancels a transaction via clearing. For partial cancellation, send an amount lower than the original authorization.
+
+
+
+ Use the `authorization_code` from the original authorization.
+
+
+
+```json
+{
+ "transaction_type": "clearing_cancellation",
+ "card_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "amount": "100.50",
+ "currency": "USD",
+ "authorization_code": "ABC123"
+}
+```
+
+
+
+ The simulator will:
+ - Validate the original authorization
+ - Process the cancellation
+ - Adjust balances accordingly
+
+
+ For partial cancellations, use an amount lower than the original authorization amount.
+
+
+
+
+## Response Handling
+
+### Approved (Authorization)
+
+An approved authorization response includes full transaction details:
+
+```json
+{
+ "status": "approved",
+ "authorization_code": "ABC123",
+ "authorization_id": 98765432,
+ "authorization_date_time": "2025-06-15T14:30:00Z",
+ "settlement_amount": "100.50",
+ "mode_type": "DEBIT",
+ "card_mode": "CHIP",
+ "is_domestic_transaction": true
+}
+```
+
+### Approved (Clearing / Clearing Cancellation)
+
+Clearing responses are sparse as most fields will be empty or zero-valued:
+
+```json
+{
+ "status": "approved",
+ "authorization_code": "",
+ "authorization_id": 0,
+ "authorization_date_time": "0001-01-01T00:00:00Z",
+ "settlement_amount": "",
+ "mode_type": "",
+ "card_mode": "",
+ "is_domestic_transaction": false
+}
+```
+
+### Denied
+
+If denied, the response includes detailed denial information:
+
+```json
+{
+ "status": "denied",
+ "authorization_code": "",
+ "authorization_id": 98765432,
+ "authorization_date_time": "2025-06-15T14:30:00Z",
+ "settlement_amount": "0.00",
+ "mode_type": "DEBIT",
+ "card_mode": "CHIP",
+ "is_domestic_transaction": true,
+ "denial_code": "810",
+ "denial_reason": "Insufficient balance"
+}
+```
+
+
+ `denial_code` and `denial_reason` use the same codes documented in [Card Decline Reasons](/concepts/card/decline-codes), use the simulator to test the responses and showcase the right mapping according to the guide.
+
+
+## Error Handling
+
+Validation and authentication errors return structured error objects:
+
+```json
+{
+ "code": 400,
+ "message": "authorization_code is required for reversal, replacement, and clearing transactions"
+}
+```
+
+**Possible HTTP status codes:**
+
+| Status | Cause |
+|--------|-------|
+| `401` | Invalid credentials |
+| `400` | Validation error (missing fields, invalid amount/currency) |
+| `404` | Card or account not found |
+| `409` | Clearing collision — a clearing message is already being processed for this authorization. Wait at least 2 minutes between clearing messages |
diff --git a/guides/cards/create-virtual.mdx b/guides/cards/create-virtual.mdx
new file mode 100644
index 0000000..38337b9
--- /dev/null
+++ b/guides/cards/create-virtual.mdx
@@ -0,0 +1,168 @@
+---
+title: "Create Virtual Card"
+description: "Create and manage virtual cards for users"
+---
+
+Virtual cards are activated immediately after creation and can be used for online purchases right away.
+
+## Card Activation
+
+To create a card for a user, call [`POST /cards/virtual`](/api-reference/cards/create-virtual-card) with a `cardName`. Once successful, you will get a `cardId`.
+
+The card's `status` will first be `provisioning` until our card provider has fully created the card. This is an asynchronous task. We recommend showing this `status` to your users, and polling the `/cards` endpoint regularly until it becomes `active`. The provisioning process should not last more than 10 seconds.
+
+The request accepts an optional `phone` field (E.164 format). The behavior depends on whether the user already has a `cardholderId`:
+
+| Scenario | Result |
+|----------|--------|
+| User already has a `cardholderId` | Card created directly; `phone` is ignored |
+| No `cardholderId`, no `phone` provided | `422 PHONE_REQUIRED` |
+| No `cardholderId`, valid `phone` provided | Cardholder created via API, then card created |
+
+
+
+```bash
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/cards/virtual \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "cardName": "",
+ "phone": ""
+ }'
+```
+
+
+```bash
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/cards/virtual \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "cardName": "",
+ "phone": ""
+ }'
+```
+
+
+
+
+## Card transactions and enrichment
+
+A user's card transactions are returned as `card_transaction` entries via [`GET /user/statement`](/api-reference/user-movements/get-account-statement). Each entry includes both the raw transaction data from the card network and an `enrichment` object with matched merchant, category, and location data which lets developers build a clean, recognizable transaction feed instead of showing raw network descriptors.
+
+
+ See [Transaction Enrichment](/concepts/card/transaction-enrichment) for why this matters and how matching works conceptually.
+
+
+```json
+{
+ "data": [
+ {
+ "type": "card_transaction",
+ "id": "",
+ "status": "pending",
+ "amount": "",
+ "currency": "",
+ "decimals": 123,
+ "originalAmount": "",
+ "originalCurrency": "",
+ "originalDecimals": 123,
+ "isCredit": true,
+ "createdAt": "2023-11-07T05:31:56Z",
+ "updatedAt": "2023-11-07T05:31:56Z",
+ "description": "",
+ "authorizationId": 123,
+ "mcc": "",
+ "authorizationCode": "",
+ "merchant": {
+ "name": "",
+ "city": "",
+ "country": "",
+ "categoryCode": ""
+ },
+ "entryMode": "",
+ "billing": {
+ "billingAmount": "",
+ "billingCurrency": {
+ "symbol": "",
+ "code": "",
+ "decimals": 123,
+ "name": ""
+ }
+ },
+ "transactionCurrency": {
+ "symbol": "",
+ "code": "",
+ "decimals": 123,
+ "name": ""
+ },
+ "cardId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
+ "cardToken": "",
+ "clearedAt": "2023-11-07T05:31:56Z",
+ "isPending": true,
+ "kind": "Payment",
+ "transactions": [
+ {
+ "status": "",
+ "to": "",
+ "value": "",
+ "data": "",
+ "hash": ""
+ }
+ ],
+ "declineReason": {
+ "code": "",
+ "message": ""
+ },
+ "wallet": {
+ "provider": "apple_pay",
+ "deviceBrand": "",
+ "deviceModel": "",
+ "deviceType": "",
+ "deviceName": ""
+ },
+ "enrichment": {
+ "status": "matched",
+ "merchant": {
+ "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
+ "name": "",
+ "logoUrl": ""
+ },
+ "shop": {
+ "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
+ "type": "",
+ "category": {
+ "name": "",
+ "logoUrl": ""
+ },
+ "tags": [""],
+ "address": {
+ "street": "",
+ "city": "",
+ "zip": "",
+ "country": "",
+ "areas": [
+ {
+ "name": "",
+ "value": ""
+ }
+ ]
+ },
+ "coordinates": {
+ "latitude": 123,
+ "longitude": 123,
+ "accuracy": "",
+ "zoom": 123
+ },
+ "url": "",
+ "googlePlaceId": "",
+ "phoneNumber": ""
+ }
+ }
+ }
+ ],
+ "pagination": {
+ "nextCursor": "",
+ "hasNext": true
+ }
+}
+```
diff --git a/guides/configuring-environment.mdx b/guides/configuring-environment.mdx
new file mode 100644
index 0000000..38a256b
--- /dev/null
+++ b/guides/configuring-environment.mdx
@@ -0,0 +1,56 @@
+---
+title: "Sandbox vs Production"
+description: "Understanding the difference between the sandbox and production environments"
+---
+
+Gnosis Pay provides two separate environments for integrating with our API: **sandbox** and **production**. This page explains what each is for, who can access them, and what's available in sandbox to help you build and test your integration before going live.
+
+## Sandbox
+
+The sandbox environment is **open to all developer teams and product**, whether it is for exploring Gnosis Pay stack for the first time, building a proof of concept, or running a phased testing process ahead of a production launch.
+
+
+ All the base URLs used throughout these docs (`core.sandbox.gnosispay.in`) point to the sandbox environment, so developers start integrating testing features immediately. Partners still need to whitelist domains with us for SIWE flows.
+
+
+### Sandbox features
+
+**1. KYC testing via Sumsub sandbox**
+
+The KYC flow runs against Sumsub's sandbox environment, so developers can test the full identity verification experience using Sumsub's own test templates, without submitting any real personal data or waiting for manual approval. This includes testing different KYC outcomes (approved, resubmission requested, manual review, rejected) to make sure integration handles each status correctly. Read the **sandbox environment** guide for [testing Sumsub flow](/guides/onboarding#3-kyc-process).
+
+**2. Transaction simulator**
+
+Simulate card transactions to see how they perform in real-time across different states such as authorizations, declines, refunds, and reversals without needing a live card network connection. This lets you build and test transaction handling, webhooks, and UI states end-to-end before any real money or card is involved.
+
+
+
+
+ See [KYC Statuses](/concepts/kyc/kyc-statuses) for the full list of statuses your integration should handle.
+
+
+## Production Environment
+
+Production access is only granted when there is a partnership agreement between a partner with Gnosis Pay. As part of onboarding, Gnosis Pay team will provide you the following:
+
+- Provision **partner** access for [Partner Dashboard access](https://partners.gnosispay.com) and production APIs
+- **Whitelist product domain(s)** to allow SIWE authentication requests to be issued and verified against the application
+- Enable domain to **host secure card elements** for displaying sensitive card data (such as card numbers or CVVs) directly in application
+
+
+ Production credentials are not self-serve. If you're ready to move from sandbox testing to production, [contact sales] to begin the partnership process.
+
+
+## Choosing an environment
+
+| | Sandbox | Production |
+|---|---|---|
+| **Who can access it** | Anyone | Post partnership agreement|
+| **Requires an agreement** | No | Yes |
+| **Card activity** | Simulated on test network | Transaction happens in real-time on card network |
+| **KYC provider** | Sumsub sandbox (test documents) | Sumsub production (real documents) |
+| **Domain whitelisting required** | Yes | Yes |
+
+
+ Every endpoint in these docs includes both **Sandbox** and **Production** request examples, switch between them using the tabs on each code block.
+
diff --git a/guides/kyc-sharing/monerium.mdx b/guides/kyc-sharing/monerium.mdx
new file mode 100644
index 0000000..6be9e27
--- /dev/null
+++ b/guides/kyc-sharing/monerium.mdx
@@ -0,0 +1,137 @@
+---
+title: "Monerium IBAN Integration"
+description: "Share a user's verified KYC data with Monerium to enable IBAN issuance"
+---
+
+
+ Before starting, read [KYC Sharing (Sumsub Flow)](/guides/kyc-sharing/pass-kyc) as this guide builds directly on the share-token flow described there.
+
+
+Gnosis Pay integrates with **Monerium** to offer users an IBAN linked to their account. Rather than requiring the user to complete KYC a second time with Monerium, their already-verified Sumsub identity data can be shared directly with Monerium, which reuses it to populate and verify the user's Monerium profile.
+
+Monerium is configured as a Sumsub **recipient** on our end, meaning your integration flow requests a Sumsub share token scoped specifically for Monerium's client ID, then forwards that token to Monerium.
+
+## How it works
+
+
+
+ Call [`POST /kyc/import-partner-applicant`](/api-reference/kyc/generate-kyc-applicant-share-token) with `forClientId` set to Monerium's Sumsub client ID.
+
+
+
+```bash
+ curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/kyc/import-partner-applicant \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "forClientId": "",
+ "ttlInSecs": 1200
+ }'
+```
+
+
+```bash
+ curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/kyc/import-partner-applicant \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "forClientId": "",
+ "ttlInSecs": 1200
+ }'
+```
+
+
+
+ The response returns a single-use `token`:
+
+```json
+ {
+ "token": "",
+ "forClientId": ""
+ }
+```
+
+
+ This token is single-use and expires after `ttlInSecs` (default 1200 seconds). Request a fresh token immediately before passing it to Monerium, don't generate it ahead of time and store it.
+
+
+
+
+
+
+ This call is made directly to Monerium's API using your own Monerium partner credentials (`BearerAuth`) not a Gnosis Pay endpoint. Note Monerium's sandbox uses `.dev` (fake money) and production uses `.app` (real money),this differs from Gnosis Pay's own `.sandbox` / `.prod` domain pattern, so don't mix them up.
+
+
+ Pass the `token` from Step 1 to [Monerium's Share KYC Data endpoint](https://docs.monerium.com/api/#tag/profiles/operation/share-profile-kyc), under the `personal` object, with `provider` set to `"sumsub"`.
+
+
+
+```bash
+ curl --request POST \
+ --url "https://api.monerium.dev/profiles/{profile}/share" \
+ --header 'Authorization: Bearer ' \
+ --header 'Accept: application/vnd.monerium.api-v2+json' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "provider": "sumsub",
+ "personal": {
+ "token": ""
+ }
+ }'
+```
+
+
+```bash
+ curl --request POST \
+ --url "https://api.monerium.app/profiles/{profile}/share" \
+ --header 'Authorization: Bearer ' \
+ --header 'Accept: application/vnd.monerium.api-v2+json' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "provider": "sumsub",
+ "personal": {
+ "token": ""
+ }
+ }'
+```
+
+
+
+ Monerium uses the supplied token to fetch the user's data directly from Sumsub and populates the relevant sections of the user's Monerium profile. Each section that receives sufficient data transitions to `pending`; any section that remains incomplete stays `incomplete`.
+
+
+
+
+
+ Once Monerium has ingested the shared KYC data, the relevant sections of the user's profile move to `pending` review on Monerium's side. No further action is needed from your integration until Monerium's review completes.
+
+
+
+ Once the profile's KYC sections are approved by Monerium, you can request IBAN issuance directly through Monerium's own API.
+
+
+ See Monerium's own API reference for the IBAN issuance endpoint, this is a separate call from KYC sharing above.
+
+
+
+
+## Summary
+
+```mermaid
+sequenceDiagram
+ participant User
+ participant GnosisPay
+ participant Sumsub
+ participant Monerium
+
+ User->>GnosisPay: Authenticated request
+ GnosisPay->>Sumsub: Request share token (forClientId = Monerium)
+ Sumsub->>GnosisPay: Return single-use token
+ GnosisPay->>Monerium: POST /profiles/{profile}/share (provider: sumsub, token)
+ Monerium->>Sumsub: Fetch applicant data using token
+ Monerium->>Monerium: Populate profile, sections move to pending
+ Monerium->>GnosisPay: KYC approved
+ GnosisPay->>Monerium: Request IBAN issuance
+```
diff --git a/guides/kyc-sharing/pass-kyc.mdx b/guides/kyc-sharing/pass-kyc.mdx
new file mode 100644
index 0000000..1e15abd
--- /dev/null
+++ b/guides/kyc-sharing/pass-kyc.mdx
@@ -0,0 +1,47 @@
+---
+title: "KYC Sharing with Sumsub"
+description: "Generate a Sumsub share token to reuse a user's verified KYC identity with a partner"
+---
+
+
+
+ Read [KYC Overview](/concepts/kyc/overview) as it covers why we use Sumsub and the full KYC status lifecycle. This guide covers how to share a user's already-verified identity with a partner via Sumsub.
+
+
+If a user has already completed KYC with Gnosis Pay, that verified identity can be **reused** rather than requiring the user to go through verification again with a partner. This is done by generating a temporary **Sumsub share token**, which the partner uses on their end to import the applicant's already-verified data.
+
+## Generate KYC Applicant Share Token
+
+Generates a temporary Sumsub share token for the authenticated user's KYC applicant. Pass this token to the named Sumsub recipient (the partner) to reuse the applicant's verified identity data.
+
+
+
+```bash
+ curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/kyc/import-partner-applicant \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "forClientId": "",
+ "ttlInSecs": 1200
+ }'
+```
+
+
+```bash
+ curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/kyc/import-partner-applicant \
+ --header 'Authorization: Bearer ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "forClientId": "",
+ "ttlInSecs": 1200
+ }'
+```
+
+
+
+
+
+ The share token is **single-use** and expires after `ttlInSecs` (or Sumsub's default of 1200 seconds if not specified). Generate a new token for each sharing attempt — it cannot be reused once consumed or expired.
+
diff --git a/guides/onboarding.mdx b/guides/onboarding.mdx
new file mode 100644
index 0000000..7e4d202
--- /dev/null
+++ b/guides/onboarding.mdx
@@ -0,0 +1,433 @@
+---
+title: "Onboard to Gnosis Pay"
+description: "User onboarding using Gnosis Pay"
+---
+
+This documentation provides a step-by-step guide on how to test the user onboarding experience for Gnosis Pay for both environments.
+
+## 1. Authentication
+
+
+
+ Before proceeding, complete the SIWE authentication flow to obtain an access token. See the integration guide for [authenticating with SIWE](/guides/auth-with-siwe).
+
+
+
+## 2. User Registration
+
+
+
+ Send an email verification request to [`POST /email-verification`](/api-reference/auth/request-email-verification) with a One-Time Password (OTP) to the user's email address.
+
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/email-verification \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "email": "jsmith@example.com"
+ }'
+```
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/email-verification \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "email": "jsmith@example.com"
+ }'
+```
+
+
+
+
+
+ Register a new user with email OTP and create a user profile. POST [`/user`](/api-reference/user/register-user) endpoint returns a new access token with userID that must be used as the bearer token for all subsequent API requests — otherwise the calls will fail.
+
+ Optionally, provide a shareToken for Sumsub reusable KYC.
+
+
+ If the access token lacks a `userID`, it indicates that user registration failed because the email was never properly submitted.
+
+
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/user \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "email": "jsmith@example.com",
+ "otp": "",
+ "shareToken": ""
+ }'
+```
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/user \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "email": "jsmith@example.com",
+ "otp": "",
+ "shareToken": ""
+ }'
+```
+
+
+
+
+
+ After user registration, use the access token to retrieve the user's current onboarding status. [`GET /user/onboarding`](/api-reference/user/get-onboarding-status) will indicate the next required step in the onboarding process.
+
+ #### User Onboarding States
+
+ The onboarding status values indicate the current step and required user actions:
+
+ | Status | Description | User Action Required |
+ |--------|-------------|---------------------|
+ | `action_accept_tos` | Terms of Service acceptance required - user registered but hasn't accepted required terms | Review and accept Terms of Service |
+ | `waiting_kyc_setup` | KYC initialization in progress - all terms accepted, KYC process being set up | Wait for KYC setup completion |
+ | `action_complete_kyc` | KYC verification pending - KYC check created but pending user completion | Complete KYC verification via Sumsub `webSdkUrl` |
+ | `kyc_manual_review` | KYC provider flagged the check as requiring manual review | This is a non-recoverable state from the user's side, requires internal review for updating application status |
+ | `action_kyc_resubmission_requested` | KYC provider has requested the user resubmit their KYC documents — a new Sumsub session URL is provided | Re-complete KYC verification via Sumsub using the provided `webSdkUrl` |
+ | `action_complete_sof` | Source of Funds questionnaire required - KYC approved, SOF answers needed | Answer Source of Funds questionnaire |
+ | `action_create_account` | Ready for account creation - KYC approved and SOF completed | Proceed with account creation |
+ | `waiting_account_setup` | Account provisioning in progress - account is being set up in the system | Wait for account setup completion |
+ | `action_verify_phone` | Phone verification required, account is active but user can't create card until phone is verified.| Verify phone number |
+ | `completed` | Onboarding complete - account is active with cardholder ID | Start using the platform |
+ | `rejected` | Onboarding rejected - account is blocked, closed, or KYC verification failed | Contact support or retry if applicable |
+
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/user/onboarding
+```
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/user/onboarding
+```
+
+
+
+
+
+ At this point, the user is registered in the Gnosis Pay system and has an associated `userID`. Call the endpoint [`GET /user/onboarding`](/api-reference/user/get-onboarding-status). The response JSON will be returned with status of `action_accept_tos`.
+
+```json
+{
+ "status": "action_accept_tos",
+ "terms": [
+ {
+ "type": "string",
+ "currentVersion": "string",
+ "name": "string",
+ "url": null,
+ "accepted": true,
+ "acceptedVersion": null,
+ "acceptedAt": null
+ }
+ ]
+}
+```
+
+
+ UX tip: Handle ToS acceptance within the email registration flow to avoid introducing an additional screen in the onboarding process. In the same screen, render the Terms (or link to them) and include a mandatory "I agree to the Terms of Service" checkbox. Disable form submission until the checkbox is selected. After successful registration and token issuance, automatically trigger the SoF acceptance call with the new token.
+
+
+ #### Request Terms of Service
+
+ Fetch the current `Terms of Service` that users must agree to before continuing with the onboarding process via the endpoint [`GET /terms`](/api-reference/terms/list-available-terms).
+
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/terms
+```
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/terms
+```
+
+
+
+ Submit the accepted Terms of Service via the [`POST /user/terms`](/api-reference/terms/accept-terms) endpoint.
+
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/user/terms \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "terms": [
+ {
+ "type": "",
+ "version": ""
+ }
+ ]
+ }'
+```
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/user/terms \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "terms": [
+ {
+ "type": "",
+ "version": ""
+ }
+ ]
+ }'
+```
+
+
+
+ You can check the status of the user's acceptance of the Terms of Service via the [`GET /user/terms`](/api-reference/terms/get-user-terms-status) endpoint.
+
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/user/terms
+```
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/user/terms
+```
+
+
+
+
+
+## 3. KYC Process
+
+
+
+ Call the [`GET /user/onboarding`](/api-reference/user/get-onboarding-status) API to retrieve the current status of the user's onboarding process. If the status is `action_complete_kyc`, you can proceed with the KYC process. The response will include the status and a `webSdkURL` for completing KYC verification.
+
+```json
+{
+ "status": "action_complete_kyc",
+ "webSdkUrl": "https://in.sumsub.com/websdk/p/sbx_yeuhsxyuhkio"
+}
+```
+
+
+
+
+
+ Access the Sumsub URL provided in the response to begin the KYC verification process. In the sandbox environment, you can use Sumsub's predefined templates for testing purposes.
+
+
+ As you are in the sandbox environment, you can use fake documents or use one provided by Sumsub.
+
+
+ To complete the verification process:
+ 1. Open an iframe with the provided `webSdkUrl`
+ 2. Use the [verification document templates](https://docs.sumsub.com/docs/verification-document-templates) for Proof of Identity (POI) and Proof of Address (POA)
+ 3. Complete the liveness check as prompted
+
+
+ Access the Sumsub URL provided in the response to begin the KYC verification process.
+
+ To complete the verification process:
+ 1. Open an iframe with the provided `webSdkUrl`
+ 2. Upload valid Proof of Identity (POI) and Proof of Address (POA) documents
+ 3. Complete the liveness check as prompted
+
+
+
+
+
+ If [`GET /user/onboarding`](/api-reference/user/get-onboarding-status) returns `action_kyc_resubmission_requested`, the KYC provider has reviewed the submission and is requesting the user resubmit their documents. The response shape is identical to `action_complete_kyc` and includes a fresh `webSdkUrl`:
+
+```json
+{
+ "status": "action_kyc_resubmission_requested",
+ "webSdkUrl": "https://in.sumsub.com/websdk/p/sbx_yeuhsxyuhkio"
+}
+```
+
+ Open the Sumsub iframe again with the provided `webSdkUrl` and have the user resubmit their documents, following the same steps as the initial KYC completion.
+
+
+
+ If [`GET /user/onboarding`](/api-reference/user/get-onboarding-status) returns `kyc_manual_review`, the KYC provider has flagged the check for manual review. This is a non-recoverable state from the user's side — no `webSdkUrl` is provided and the user cannot self-resolve it.
+
+```json
+{
+ "status": "kyc_manual_review"
+}
+```
+
+
+ Display a clear message directing the user to contact customer support. No further onboarding actions are available until the manual review is resolved.
+
+
+
+
+ After completing the KYC process, the next step is to proceed to the Source of Funds (SOF) verification step. Call [`GET /user/onboarding`](/api-reference/user/get-onboarding-status), which will return the next required action to complete SOF verification along with the questions that need to be answered. Alternatively, retrieve the SOF questions directly using the [`GET /source-of-funds`](/api-reference/source-of-funds/get-sof-questions) endpoint.
+
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/source-of-funds
+```
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/source-of-funds
+```
+
+
+
+ Once all SOF questions have been reviewed and answered by the user, submit the responses through the [`POST /source-of-funds`](/api-reference/source-of-funds/submit-sof-answers) endpoint to complete this step of the onboarding process.
+
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/source-of-funds \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "answers": [
+ {
+ "question": "",
+ "answer": ""
+ }
+ ]
+ }'
+```
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/source-of-funds \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "answers": [
+ {
+ "question": "",
+ "answer": ""
+ }
+ ]
+ }'
+```
+
+
+
+
+
+## 4. Account Setup
+
+
+
+ Check the user's onboarding status using the [`GET /user/onboarding`](/api-reference/user/get-onboarding-status) endpoint to determine if their KYC verification has been accepted. If the KYC is approved, the user status will transition to the following:
+
+```json
+{
+ "status": "action_create_account"
+}
+```
+
+ In the next step, we will create the GP spending Safe wallet address.
+
+
+
+ In this step, you will initiate the Gnosis Pay account provisioning and creation process. Call [`POST /user/account`](/api-reference/user-account/create-account) endpoint to create an account for the authenticated user.
+
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.sandbox.gnosispay.in/user-api/user/account \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "celoConfig": {
+ "dailyLimits": {
+ "usdt": 1,
+ "usdc": 1
+ }
+ }
+ }'
+```
+
+
+```bash cURL
+curl --request POST \
+ --url https://core.prod.gnosispay.com/user-api/user/account \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "celoConfig": {
+ "dailyLimits": {
+ "usdt": 1,
+ "usdc": 1
+ }
+ }
+ }'
+```
+
+
+
+ Once the account provisioning begins, the onboarding status will be updated to the `waiting_account_setup` state, indicating that the account is being set up in the system.
+
+```json
+{
+ "status": "waiting_account_setup"
+}
+```
+
+
+
+ Call the [`GET /user`](/api-reference/user/get-current-user) endpoint to retrieve the full user profile, including their GP spending wallet address.
+
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.sandbox.gnosispay.in/user-api/user \
+ --header 'Content-Type: application/json'
+```
+
+
+```bash cURL
+curl --request GET \
+ --url https://core.prod.gnosispay.com/user-api/user \
+ --header 'Content-Type: application/json'
+```
+
+
+
+
+
+## 5. Phone Verification
+
+
+
+ Once the account has provisioned and is active, [`GET /user/onboarding`](/api-reference/user/get-onboarding-status) may return `action_verify_phone`.
+
+```json
+{
+ "status": "action_verify_phone"
+}
+```
+ Prompt the user to verify their phone number to proceed. Once verification is complete, the onboarding status will move to `completed`.
+
+
diff --git a/cards/assets/css-styling.png b/guides/pse/assets/css-styling.png
similarity index 100%
rename from cards/assets/css-styling.png
rename to guides/pse/assets/css-styling.png
diff --git a/guides/pse/pse-integration.mdx b/guides/pse/pse-integration.mdx
new file mode 100644
index 0000000..eba2850
--- /dev/null
+++ b/guides/pse/pse-integration.mdx
@@ -0,0 +1,501 @@
+---
+title: "PSE Integration"
+description: "Securely display and manage card data using the Gnosis Pay Payment Secure Elements (PSE) SDK"
+---
+
+
+ New to authentication on Gnosis Pay? Read [Authentication & Tokens](/concepts/auth/token) first the PSE SDK relies on a valid access token (`authModuleToken`) obtained via the [SIWE authentication flow](/guides/auth-with-siwe).
+
+
+The **Payment Secure Elements (PSE) SDK** lets you display and manage sensitive card data such as card number, expiration, CVV, and PIN directly in your application, without that data ever touching your own front-end or back-end code. Card data is rendered inside **PCI-compliant iframes** hosted by Gnosis Pay, and communicates with your app only through secure, origin-verified `postMessage` events.
+
+
+
+ PSE v3 requires a wallet signature (EIP-712) before each sensitive operation, adding a second factor on top of your `authModuleToken`. This is the current supported version.
+
+
+---
+
+## Installation
+
+Install via npm:
+
+```bash
+npm install @gnosispay/pse-sdk
+```
+
+Or load directly via CDN:
+
+```html
+
+
+
+
+
+```
+
+---
+
+## Backend Setup: mTLS and the Ephemeral Token
+
+Before initializing the SDK on the front-end, your **backend** must establish a secure connection to the PSE private API to obtain an **ephemeral token**.
+
+### Secure connection using mTLS authentication
+
+**Mutual TLS (mTLS)** is a form of authentication where both parties in a connection verify each other using the TLS protocol. Your backend establishes an mTLS connection with the Gnosis Pay private PSE API to receive an ephemeral token.
+
+#### Generating mTLS certificates
+
+After signing up through the [Partners Dashboard](https://partners.gnosispay.com/), you'll receive an `App ID` instantly. Use it to generate a private key and Certificate Signing Request (CSR):
+
+```bash
+# APP_ID is a string starting with `gp_` that you have received from Gnosis Pay
+export APP_ID="gp_woop_123"
+
+# Create a private key (NEVER share with anyone)
+openssl ecparam -name prime256v1 -genkey -noout -out "${APP_ID}.key.pem"
+
+# Create the CSR (OK to share)
+openssl req -new -sha256 -key "${APP_ID}.key.pem" -out "${APP_ID}.csr.pem" -subj "/CN=${APP_ID}"
+```
+
+
+ Share only `${APP_ID}.csr.pem` with the Gnosis Pay team. **Never** share the `.key.pem` private key file with anyone.
+
+
+Once we receive your CSR, we'll sign it and return your signed certificates. These, along with your private key, are used to establish the mTLS connection.
+
+#### Establishing mTLS authentication (Node.js)
+
+Store your signed certificates and private key securely in your environment:
+
+```bash
+SIGNED_CERTIFICATES="-----BEGIN CERTIFICATE-----
+ABCQz ....
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+DEFC7 ....
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+GHICc ....
+-----END CERTIFICATE-----"
+
+PRIVATE_KEY="-----BEGIN EC PRIVATE KEY-----
+ABCD....
+-----END EC PRIVATE KEY-----"
+```
+
+
+
+```js Using Axios
+const httpsAgent = new https.Agent({
+ cert: process.env.SIGNED_CERTIFICATES,
+ key: process.env.PRIVATE_KEY,
+ rejectUnauthorized: true, // Ensure SSL verification
+});
+
+const ephemeralTokenRequest = await axios({
+ httpsAgent: httpsAgent,
+ method: "POST",
+ url: `https://api-pse.gnosispay.com/api/v1/ephemeral-token`,
+ headers: { "Content-Type": "application/json" },
+});
+```
+
+```js Using https.request
+import https from "https";
+
+const httpsAgent = new https.Agent({
+ cert: CERT,
+ key: KEY,
+ rejectUnauthorized: true,
+});
+
+const req = https.request(
+ {
+ hostname: "api-pse.gnosispay.com",
+ path: "/api/v1/ephemeral-token",
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "User-Agent": "User-Client/1.0.0",
+ },
+ agent: httpsAgent,
+ },
+ (res) => {
+ let data = "";
+ res.on("data", (chunk) => {
+ data += chunk;
+ });
+
+ res.on("end", () => {
+ console.log("Status:", res.statusCode);
+ try {
+ const parsedData = JSON.parse(data);
+ console.log("Response:", parsedData);
+ } catch {
+ console.log("Raw response:", data);
+ }
+ });
+ }
+);
+
+req.on("error", (error) => {
+ console.error("Request error:", error);
+});
+req.end();
+```
+
+
+
+
+ The ephemeral token is valid for a very short time frame. Generate a new one for every SDK usage.
+
+
+### Backend: ephemeral token relay endpoint
+
+Your backend needs an endpoint that proxies ephemeral token requests to the PSE private API using the mTLS setup above. Example using Express:
+
+```js
+import express from "express";
+import axios from "axios";
+import https from "node:https";
+
+const app = express();
+
+app.get("/api/ephemeral-token", async (_req, res) => {
+ try {
+ const cert = Buffer.from(process.env.CLIENT_CERT, "base64").toString("ascii");
+ const key = Buffer.from(process.env.CLIENT_KEY, "base64").toString("ascii");
+ const httpsAgent = new https.Agent({ cert, key, rejectUnauthorized: true });
+
+ const response = await axios({
+ method: "POST",
+ url: "https://api-pse.gnosispay.com/api/v1/ephemeral-token",
+ headers: { "Content-Type": "application/json" },
+ httpsAgent,
+ });
+
+ res.json({ data: response.data.data });
+ } catch (error) {
+ res.status(502).json({ error: "Failed to reach PSE private API" });
+ }
+});
+```
+
+`CLIENT_CERT` and `CLIENT_KEY` are the base64-encoded signed certificate and private key stored in your environment variables.
+
+---
+
+## EIP-712 Two-Factor Authentication
+
+PSE v3 requires a **wallet signature** before each sensitive operation. This acts as a second factor: even if an `authModuleToken` is compromised, an attacker cannot view card data or change a PIN without also controlling the user's wallet.
+
+### How it works
+
+Before initializing the SDK, your front-end must:
+
+1. Request a one-time **challenge** from the auth module.
+2. Ask the user's wallet to **sign** the returned EIP-712 typed data.
+3. Pass the resulting **signature** and **nonce** to the SDK constructor.
+
+The PSE service forwards both values to the auth module, which verifies the signature and marks the nonce as consumed. Each challenge is **single-use** and **expires after 5 minutes**.
+
+### Get PCI EIP-712 Challenge
+
+Issues a one-time EIP-712 challenge. The response is a complete typed-data object that can be passed directly to `signTypedData` (convert `message.nonce` to `BigInt` first).
+
+
+
+```bash
+ curl --request GET \
+ --url "https://core.sandbox.gnosispay.in/user-api/pci/cards/{cardId}/challenge?action=view-details" \
+ --header 'Authorization: Bearer '
+```
+
+
+```bash
+ curl --request GET \
+ --url "https://core.prod.gnosispay.com/user-api/pci/cards/{cardId}/challenge?action=view-details" \
+ --header 'Authorization: Bearer '
+```
+
+
+
+
+
+ `message.nonce` is returned as a decimal string representing a `uint256`. Convert it to `BigInt` before passing it to `signTypedData`.
+
+
+### Signing the challenge
+
+
+
+```typescript Using wagmi
+import { useSignTypedData } from "wagmi";
+
+const { signTypedDataAsync } = useSignTypedData();
+
+// 1. Fetch the challenge (authModuleToken is sent automatically via client config)
+const { data, error } = await getPciCardsByCardIdChallenge({
+ path: { cardId },
+ query: { action: "view-details" },
+});
+
+if (error || !data) throw new Error("Failed to get EIP-712 challenge");
+
+// 2. Sign and convert nonce to BigInt for the uint256 type
+const signature = await signTypedDataAsync({
+ domain: data.domain,
+ types: data.types,
+ primaryType: data.primaryType,
+ message: {
+ authorization: data.message.authorization,
+ nonce: BigInt(data.message.nonce),
+ },
+});
+
+// 3. Pass to SDK constructor
+const eip712Signature = signature;
+const eip712Nonce = data.message.nonce; // keep as decimal string
+```
+
+```typescript Using viem directly
+import { createWalletClient, custom } from "viem";
+import { celo } from "viem/chains";
+
+const walletClient = createWalletClient({
+ chain: celo,
+ transport: custom(window.ethereum),
+});
+
+// 1. Fetch the challenge
+const response = await fetch(
+ `https://core.sandbox.gnosispay.in/user-api/pci/cards/${cardId}/challenge?action=view-details`,
+ { headers: { Authorization: `Bearer ${authModuleToken}` } }
+);
+const data = await response.json();
+
+// 2. Sign
+const [account] = await walletClient.getAddresses();
+const signature = await walletClient.signTypedData({
+ account,
+ domain: data.domain,
+ types: data.types,
+ primaryType: data.primaryType,
+ message: {
+ authorization: data.message.authorization,
+ nonce: BigInt(data.message.nonce),
+ },
+});
+
+const eip712Signature = signature;
+const eip712Nonce = data.message.nonce;
+```
+
+
+
+
+ The challenge must be fetched **immediately before** each SDK initialization. Do not reuse a nonce across different operations or SDK instances as it will be rejected after the first use.
+
+
+---
+
+## Initialize the SDK
+
+After completing the EIP-712 challenge/sign step above, initialize the SDK with `pseVersion: 3`:
+
+```typescript
+import GPSDK, { ElementType } from "@gnosispay/pse-sdk";
+
+// 1. Get the auth module access token from your SIWE auth flow
+const authModuleToken = getAccessToken(); // your auth implementation
+
+// 2. Fetch ephemeral token from your backend
+const response = await fetch("/api/ephemeral-token");
+const { data } = await response.json();
+
+// 3. Fetch and sign an EIP-712 challenge (see section above)
+// Use the action matching the operation you are about to perform:
+// "view-details" | "view-pin" | "change-pin"
+const { eip712Signature, eip712Nonce } = await getSignedChallenge(cardId, "view-details");
+
+// 4. Initialize the SDK with PSE version 3
+const gpSdk = new GPSDK({
+ pseVersion: 3, // PSE version 3, required for EIP-712 2FA
+ appId: "gp_your_app_id", // Your Partner App ID
+ ephemeralToken: data.ephemeralToken,
+ authModuleToken: authModuleToken, // Auth module access token
+ eip712Signature: eip712Signature, // Hex signature from wallet
+ eip712Nonce: eip712Nonce, // Decimal nonce string from challenge
+ onActionSuccess: (action) => {
+ console.log("Action completed:", action);
+ },
+ onInvalidToken: (message) => {
+ console.error("Token invalid:", message);
+ // Refresh the ephemeral token and reinitialize
+ },
+ onError: (message, details) => {
+ console.error("PSE error:", message, details);
+ },
+});
+```
+
+
+ The `authModuleToken` expires every 15 minutes. Handle the `onInvalidToken` callback to refresh your access token via the [Authenticating with SIWE](guides/auth-with-siwe#refresh-access-token) flow and re-initialize the SDK.
+
+
+### Display card details
+
+Use `ElementType.CardData` to display the full card number, expiration date, and security code.
+
+
+ Use `action: "view-details"` when fetching the EIP-712 challenge for this element.
+
+
+```typescript
+// cardId is a UUID obtained from GET /cards
+const { destroy } = gpSdk.init(ElementType.CardData, "#card-data-container", {
+ cardId: "019c9578-a8ce-7445-9961-51b945605f70",
+});
+
+// Call destroy() when unmounting or cleaning up
+destroy();
+```
+
+### View card PIN
+
+Use `ElementType.CardPin` to display the card's current PIN inside the secure iframe.
+
+
+ Use `action: "view-pin"` when fetching the EIP-712 challenge for this element.
+
+
+```typescript
+// Fetch and sign the challenge with action "view-pin" before constructing the SDK
+const { eip712Signature, eip712Nonce } = await getSignedChallenge(cardId, "view-pin");
+
+const gpSdk = new GPSDK({
+ pseVersion: 3,
+ appId: "gp_your_app_id",
+ ephemeralToken: data.ephemeralToken,
+ authModuleToken: authModuleToken,
+ eip712Signature,
+ eip712Nonce,
+ onActionSuccess: (action) => { /* ... */ },
+ onInvalidToken: (message) => { /* ... */ },
+ onError: (message, details) => { /* ... */ },
+});
+
+const { destroy } = gpSdk.init(ElementType.CardPin, "#pin-container", {
+ cardId: "019c9578-a8ce-7445-9961-51b945605f70",
+});
+```
+
+### Set / change card PIN
+
+Use `ElementType.SetCardPin` to render a PIN entry form that lets the cardholder set or change their PIN.
+
+
+ Use `action: "change-pin"` when fetching the EIP-712 challenge for this element.
+
+
+```typescript
+// Fetch and sign the challenge with action "change-pin" before constructing the SDK
+const { eip712Signature, eip712Nonce } = await getSignedChallenge(cardId, "change-pin");
+
+const gpSdk = new GPSDK({
+ pseVersion: 3,
+ appId: "gp_your_app_id",
+ ephemeralToken: data.ephemeralToken,
+ authModuleToken: authModuleToken,
+ eip712Signature,
+ eip712Nonce,
+ onActionSuccess: (action) => {
+ // Fired with Action.SetPin when the user submits the new PIN,
+ // and Action.DoneSettingPin when the operation is confirmed.
+ console.log("PIN operation completed:", action);
+ },
+ onInvalidToken: (message) => { /* ... */ },
+ onError: (message, details) => { /* ... */ },
+});
+
+const { destroy } = gpSdk.init(ElementType.SetCardPin, "#set-pin-container", {
+ cardId: "019c9578-a8ce-7445-9961-51b945605f70",
+});
+```
+
+### Refresh the ephemeral token
+
+If the current ephemeral token has expired, you'll receive an `onInvalidToken` callback. Refresh it without re-creating the SDK instance:
+
+```typescript
+const newToken = await fetchNewEphemeralToken();
+gpSdk.refreshToken(newToken);
+```
+
+---
+
+## Available Elements
+
+| Element | Description |
+|---|---|
+| `ElementType.CardData` | Read credit card number, expiration date and CVV |
+| `ElementType.CardPin` | Read PIN of credit card |
+| `ElementType.SetCardPin` | Set PIN of credit card |
+| `ElementType.CardExpirationCopied` | User copied card expiration date |
+| `ElementType.CardSecurityCodeCopied` | User copied card security code |
+| `ElementType.CardNumberCopied` | User copied card number |
+
+Each element is rendered in a secure iframe to ensure PCI compliance.
+
+## Element Lifecycle
+
+Elements can be initialized and destroyed:
+
+```js
+const cardDataContainer = gpSdk.init(
+ ElementType.CardData,
+ "#card-data-container",
+ {
+ cardId: "your-card-id",
+ }
+);
+
+// When you're done with the element
+cardDataContainer.destroy();
+```
+
+## Callbacks
+
+The SDK provides callbacks to handle events from the iframe elements:
+
+| Callback | Trigger |
+|----------|---------|
+| `onActionSuccess(action)` | A user action completes (e.g., `CardNumberCopied`, `SetPin`, `DoneSettingPin`) |
+| `onInvalidToken(message)` | The ephemeral token has expired or is invalid |
+| `onError(message, details)` | An error occurred inside the iframe |
+
+---
+
+## Customizing Element Styling
+
+For security reasons, the only way to apply custom styling to iframe elements is to prepare and share a **CSS file** with the Gnosis Pay team. This file, named `.css`, will be incorporated into the iframe.
+
+Standard styling is applied to iframe elements by default. Selectors you can override include:
+
+- `.pse-container` : shared class for all iframe containers
+- `#pse-card-data-container` : main container for displaying card data
+- `.pse-card-field` : container for each card data field (card number, expiry date, security code)
+- `.pse-card-label` : labels for each field
+- `.pse-card-value` : container for the actual card data values
+
+### Styling workflow
+
+1. In your front-end, load the element you wish to customize (e.g., the card data).
+2. Locate the custom CSS file with your name in either the "**Style Editor**" in Firefox or the "**Sources**" panel in Chrome/Brave (e.g., `gnosis_pay_ui.css`).
+3. Apply your desired styling changes reflect immediately in your interface.
+4. Save the file and send it to Gnosis Pay for application in production.
diff --git a/guides/pse/pse.mdx b/guides/pse/pse.mdx
new file mode 100644
index 0000000..7a3d00c
--- /dev/null
+++ b/guides/pse/pse.mdx
@@ -0,0 +1,60 @@
+---
+title: Partner Secure Elements (PSE)
+description: Display sensitive card information and manage PINs securely in your client application using PSE SDK (PSE version 3 with EIP-712 two-factor authentication).
+---
+
+## Overview
+
+If you want to display sensitive information (such as card numbers or PINs) in your front-end, you'll need to interact with our **Partner Secure Elements (PSE)** service. The easiest way to do this is by using the [PSE SDK](https://www.npmjs.com/package/@gnosispay/pse-sdk) from Gnosis Pay.
+
+To initialize the SDK, you'll need:
+- An `App ID` provided to you upon registration with Gnosis Pay
+- An **ephemeral-token** retrieved from the PSE private API using mTLS authentication
+- An **auth module token** obtained through the [SIWE authentication flow](/guides/auth-with-siwe)
+- An **EIP-712 signature** and **nonce** obtained from the challenge flow described below
+
+
+ **PSE version 3** adds an EIP-712 wallet signature as a second factor for every sensitive operation. Pass `pseVersion: 3` when constructing the SDK and include `eip712Signature` and `eip712Nonce` obtained from the challenge flow described below.
+
+ Note: `pseVersion` refers to the PSE SDK protocol version and is unrelated to the Gnosis Pay API path (which remains `/v2`).
+
+
+
+ **Backend Required**: mTLS authentication can only be performed from a
+ back-end. You need a back-end responsible for retrieving the
+ ephemeral-token and sending it to your front-end upon request. We'll go
+ through each step in this guide.
+
+
+Once your front-end has the ephemeral-token and auth module token, it can initialize the PSE SDK and use it to display secure elements.
+
+Here's a diagram showing each step:
+
+```mermaid
+ sequenceDiagram
+ participant FE as Your Frontend
+ participant BE as Your Backend
+ participant Auth as Auth Module
+ participant PSE as PSE API
+
+ FE->>Auth: SIWE Login
+ Auth-->>FE: authModuleToken (15min access token)
+
+ FE->>BE: Request ephemeral-token
+ BE->>PSE: POST /api/v1/ephemeral-token (mTLS)
+ PSE-->>BE: ephemeral-token
+ BE-->>FE: ephemeral-token
+
+ FE->>Auth: GET /pci/cards/{cardId}/challenge?action=...
+ Auth-->>FE: EIP-712 typed data (domain, types, message, nonce)
+ Note over FE: User signs typed data in wallet
+
+ Note over FE: Initialize PSE SDK (PSE version 3) with ephemeralToken, authModuleToken, appId, eip712Signature, eip712Nonce
+
+ FE->>PSE: SDK requests card data
+ PSE->>Auth: Verifies EIP-712 signature + nonce
+ Auth-->>PSE: Signature valid
+ PSE-->>FE: Renders card data in secure iframe
+```
+
+---
diff --git a/guides/webhooks/partner-webhook.png b/guides/webhooks/partner-webhook.png
new file mode 100644
index 0000000..7b9e0df
Binary files /dev/null and b/guides/webhooks/partner-webhook.png differ
diff --git a/guides/webhooks/webhook-events.mdx b/guides/webhooks/webhook-events.mdx
new file mode 100644
index 0000000..c557451
--- /dev/null
+++ b/guides/webhooks/webhook-events.mdx
@@ -0,0 +1,672 @@
+---
+title: "Webhook Events"
+description: "Complete list of webhook events triggered in V2"
+---
+
+## Account Events
+
+### 1. Account.balance.changed
+
+Triggered when the account balance changes.
+
+#### Event Trigger Points
+
+| Flow | Reason Value |
+| ----------------------------- | ------------------------------- |
+| Deposit approved | `deposit.approved` |
+| Deposit rejected | `deposit.rejected` |
+| Withdrawal completed | `withdrawal.completed` |
+| Instant withdrawal reconciled | `withdrawal.completed` |
+| Card authorization | `card.authorization.{category}` |
+
+
+```typescript account.balance.changed
+{
+ "id": "evt_abc123def456...",
+ "type": "account.balance.changed",
+ "createdAt": "2026-03-30T12:00:00.000000000Z",
+ "data": {
+ "accountId": "550e8400-e29b-41d4-a716-446655440000",
+ "reason": "deposit.approved",
+ "referenceId": "ref-123",
+ "balances": [
+ {
+ "currency": "EUR",
+ "decimals": 18,
+ "spendable": "1000000000000000000",
+ "nonSpendable": "500000000000000000",
+ "processingDeposits": "200000000000000000",
+ "processingWithdrawals": "100000000000000000"
+ },
+ {
+ "currency": "GBP",
+ "decimals": 18,
+ "spendable": "0",
+ "nonSpendable": "0",
+ "processingDeposits": "0",
+ "processingWithdrawals": "0"
+ },
+ {
+ "currency": "USD",
+ "decimals": 6,
+ "spendable": "1000000",
+ "nonSpendable": "50000",
+ "processingDeposits": "100000",
+ "processingWithdrawals": "0"
+ }
+ ]
+ }
+ }
+```
+
+
+### 2. Account.created
+
+Triggered when a new account is created and provisioning begins.
+
+
+```typescript account.created
+{
+ "id": "evt_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
+ "type": "account.created",
+ "createdAt": "2026-03-11T14:30:00.123456789Z",
+ "data": {
+ "id": "019505a1-b2c3-7d4e-a5f6-a1b2c3d4e5f6",
+ "kycProfileId": "019505a1-c3d4-7e5f-b6a7-b2c3d4e5f6a7",
+ "safeOwnerAddress": "0x1234567890abcdef1234567890abcdef12345678",
+ "safeAddress": null,
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "reference": null,
+ "nativeCurrency": "EUR",
+ "additionalCurrencies": ["GBP"],
+ "createdAt": "2026-03-11T14:30:00.123456789Z",
+ "updatedAt": "2026-03-11T14:30:00.123456789Z",
+ "closedAt": null,
+ "status": "provisioning",
+ "provisionedAt": null
+ }
+}
+```
+
+
+### 3. Account.activated
+
+Triggered when account provisioning is complete and account becomes active.
+
+
+```typescript account.activated
+{
+ "id": "evt_b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7",
+ "type": "account.activated",
+ "createdAt": "2026-03-11T15:00:00.123456789Z",
+ "data": {
+ "id": "019505a1-b2c3-7d4e-a5f6-a1b2c3d4e5f6",
+ "kycProfileId": "019505a1-c3d4-7e5f-b6a7-b2c3d4e5f6a7",
+ "safeOwnerAddress": "0x1234567890abcdef1234567890abcdef12345678",
+ "safeAddress": "0xabcdef1234567890abcdef1234567890abcdef12",
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "reference": "partner-ref-123",
+ "nativeCurrency": "EUR",
+ "additionalCurrencies": ["GBP"],
+ "createdAt": "2026-03-11T14:30:00.123456789Z",
+ "updatedAt": "2026-03-11T15:00:00.123456789Z",
+ "closedAt": null,
+ "status": "active",
+ "provisionedAt": "2026-03-11T14:45:00.123456789Z"
+ }
+}
+```
+
+
+### 4. Account.blocked
+
+Triggered when an account is blocked due to security or compliance reasons.
+
+
+```typescript account.blocked
+{
+ "id": "evt_c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8",
+ "type": "account.blocked",
+ "createdAt": "2026-03-11T16:00:00.123456789Z",
+ "data": {
+ "id": "019505a1-b2c3-7d4e-a5f6-a1b2c3d4e5f6",
+ "kycProfileId": "019505a1-c3d4-7e5f-b6a7-b2c3d4e5f6a7",
+ "safeOwnerAddress": "0x1234567890abcdef1234567890abcdef12345678",
+ "safeAddress": "0xabcdef1234567890abcdef1234567890abcdef12",
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "reference": "partner-ref-123",
+ "nativeCurrency": "EUR",
+ "additionalCurrencies": ["GBP"],
+ "createdAt": "2026-03-11T14:30:00.123456789Z",
+ "updatedAt": "2026-03-11T16:00:00.123456789Z",
+ "closedAt": null,
+ "status": "blocked",
+ "provisionedAt": "2026-03-11T14:45:00.123456789Z"
+ }
+}
+```
+
+
+## KYC Events
+
+### 5. KYC.profile.approved
+
+Triggered when a KYC profile verification is approved.
+
+
+```typescript kyc.profile.approved
+{
+ "id": "evt_d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9",
+ "type": "kyc.profile.approved",
+ "createdAt": "2026-03-11T14:00:00.123456789Z",
+ "data": {
+ "id": "019505a1-c3d4-7e5f-b6a7-b2c3d4e5f6a7",
+ "reference": "applicant-abc123",
+ "email": "user@example.com",
+ "status": "approved",
+ "tenantId": "tenant-xyz",
+ "details": {
+ "fullName": "John Doe",
+ "phoneNumber": "+441234567890",
+ "dateOfBirth": "1990-01-15T00:00:00Z",
+ "nationality": "GB",
+ "countryOfResidence": "GB",
+ "countryOfBirth": "GB",
+ "documentNumber": "AB123456C",
+ "gender": "male",
+ "addresses": [
+ {
+ "id": "019505a1-e5f6-7a7b-c8d9-e0f1a2b3c4d5",
+ "country": "GB",
+ "postalCode": "SW1A 1AA",
+ "city": "London",
+ "state": "England",
+ "address1": "10 Downing Street",
+ "address2": null
+ }
+ ]
+ }
+ }
+}
+```
+
+
+### 6. KYC.profile.rejected
+
+Triggered when a KYC profile verification is rejected.
+
+
+```typescript kyc.profile.rejected
+{
+ "id": "evt_e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0",
+ "type": "kyc.profile.rejected",
+ "createdAt": "2026-03-11T14:00:00.123456789Z",
+ "data": {
+ "id": "019505a1-c3d4-7e5f-b6a7-b2c3d4e5f6a7",
+ "reference": "applicant-abc123",
+ "email": "user@example.com",
+ "status": "rejected",
+ "tenantId": "tenant-xyz",
+ "details": {
+ "fullName": "John Doe",
+ "phoneNumber": "+441234567890",
+ "dateOfBirth": "1990-01-15T00:00:00Z",
+ "nationality": "GB",
+ "countryOfResidence": "GB",
+ "countryOfBirth": "GB",
+ "documentNumber": "AB123456C",
+ "gender": "male",
+ "addresses": [
+ {
+ "id": "019505a1-e5f6-7a7b-c8d9-e0f1a2b3c4d5",
+ "country": "GB",
+ "postalCode": "SW1A 1AA",
+ "city": "London",
+ "state": "England",
+ "address1": "10 Downing Street",
+ "address2": null
+ }
+ ]
+ }
+ }
+}
+```
+
+
+### 7. KYC.profile.requires_action
+
+Triggered when a KYC profile requires additional action from the user.
+
+
+```typescript kyc.profile.requires_action
+{
+ "id": "evt_f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1",
+ "type": "kyc.profile.requires_action",
+ "createdAt": "2026-03-11T14:00:00.123456789Z",
+ "data": {
+ "id": "019505a1-c3d4-7e5f-b6a7-b2c3d4e5f6a7",
+ "reference": "applicant-abc123",
+ "email": "user@example.com",
+ "status": "requires_action",
+ "tenantId": "tenant-xyz",
+ "details": null
+ }
+}
+```
+
+
+### 8. KYC.profile.resubmission_requested
+
+Triggered when KYC profile requires document resubmission.
+
+
+```typescript kyc.profile.resubmission_requested
+{
+ "id": "evt_a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2",
+ "type": "kyc.profile.resubmission_requested",
+ "createdAt": "2026-03-11T14:00:00.123456789Z",
+ "data": {
+ "id": "019505a1-c3d4-7e5f-b6a7-b2c3d4e5f6a7",
+ "reference": "applicant-abc123",
+ "email": "user@example.com",
+ "status": "resubmission_requested",
+ "tenantId": "tenant-xyz",
+ "details": null
+ }
+}
+```
+
+
+### 9. KYC.terms.approved
+
+Triggered when all required terms are accepted.
+
+
+```typescript kyc.terms.approved
+{
+ "id": "evt_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
+ "type": "kyc.terms.approved",
+ "createdAt": "2026-03-17T10:30:00.000000000Z",
+ "data": {
+ "profileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
+ "checkType": "terms",
+ "status": "approved",
+ "reference": "partner-user-ref-123"
+ }
+}
+```
+
+
+### 10. KYC.source_of_funds.approved
+
+Triggered when source of funds questionnaire is submitted and approved.
+
+
+```typescript kyc.source_of_funds.approved
+{
+ "id": "evt_b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7",
+ "type": "kyc.source_of_funds.approved",
+ "createdAt": "2026-03-17T10:35:00.000000000Z",
+ "data": {
+ "profileId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
+ "checkType": "source_of_funds",
+ "status": "approved",
+ "reference": "partner-user-ref-123"
+ }
+}
+```
+
+
+## Deposit Events
+
+### 11. Deposit.pending
+
+Triggered when an on-chain deposit is detected and awaiting KYT processing.
+
+
+```typescript deposit.pending
+{
+ "id": "evt_c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8",
+ "type": "deposit.pending",
+ "createdAt": "2026-03-17T11:00:00.000000000Z",
+ "data": {
+ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "status": "pending",
+ "amount": "1000000",
+ "currency": "USDCe",
+ "decimals": 6,
+ "transactionHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "createdAt": "2026-03-17T10:59:30.000000000Z"
+ }
+}
+```
+
+
+### 12. Deposit.approved
+
+Triggered when a deposit is confirmed after KYT and funds become available.
+
+
+```typescript deposit.approved
+{
+ "id": "evt_d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9",
+ "type": "deposit.approved",
+ "createdAt": "2026-03-17T11:00:00.000000000Z",
+ "data": {
+ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "status": "approved",
+ "amount": "1000000",
+ "currency": "USDCe",
+ "decimals": 6,
+ "transactionHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "createdAt": "2026-03-17T10:59:30.000000000Z"
+ }
+}
+```
+
+
+### 13. Deposit.rejected
+
+Triggered when a deposit is rejected by KYT.
+
+
+```typescript deposit.rejected
+{
+ "id": "evt_e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0",
+ "type": "deposit.rejected",
+ "createdAt": "2026-03-17T11:00:00.000000000Z",
+ "data": {
+ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "status": "rejected",
+ "amount": "1000000",
+ "currency": "USDCe",
+ "decimals": 6,
+ "transactionHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "createdAt": "2026-03-17T10:59:30.000000000Z"
+ }
+}
+```
+
+
+## Withdrawal Events
+
+### 14. Withdrawal.completed
+
+Triggered when a withdrawal is successfully processed on-chain.
+
+
+```typescript withdrawal.completed
+{
+ "id": "evt_f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1",
+ "type": "withdrawal.completed",
+ "createdAt": "2026-03-17T12:15:00.000000000Z",
+ "data": {
+ "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "status": "completed",
+ "amount": "500000",
+ "currency": "USDCe",
+ "decimals": 6,
+ "transactionHash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "createdAt": "2026-03-17T12:10:00.000000000Z"
+ }
+}
+```
+
+
+### 15. Withdrawal.failed
+
+Triggered when a withdrawal fails at any stage.
+
+
+```typescript withdrawal.failed
+{
+ "id": "evt_a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2",
+ "type": "withdrawal.failed",
+ "createdAt": "2026-03-17T12:15:00.000000000Z",
+ "data": {
+ "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "status": "failed",
+ "amount": "500000",
+ "currency": "USDCe",
+ "decimals": 6,
+ "transactionHash": "",
+ "chain": {
+ "name": "gnosis",
+ "id": "100"
+ },
+ "createdAt": "2026-03-17T12:10:00.000000000Z"
+ }
+}
+```
+
+
+## Card Events
+
+### 16. Card.created
+
+Triggered when a virtual card is provisioned or physical card reaches pending activation.
+
+
+```typescript card.created
+{
+ "id": "evt_b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3",
+ "type": "card.created",
+ "createdAt": "2026-03-17T14:00:00.000000000Z",
+ "data": {
+ "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "type": "virtual",
+ "status": "created",
+ "last4": "4321",
+ "createdAt": "2026-03-17T14:00:00.000000000Z"
+ }
+}
+```
+
+
+### 17. Card.activated
+
+Triggered when a physical card is activated.
+
+
+```typescript card.activated
+{
+ "id": "evt_c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4",
+ "type": "card.activated",
+ "createdAt": "2026-03-17T15:00:00.000000000Z",
+ "data": {
+ "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "type": "plastic",
+ "status": "activated",
+ "last4": "4321",
+ "createdAt": "2026-03-17T14:00:00.000000000Z"
+ }
+}
+```
+
+
+### 18. Card.blocked
+
+Triggered when a card is temporarily blocked.
+
+
+```typescript card.blocked
+{
+ "id": "evt_d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5",
+ "type": "card.blocked",
+ "createdAt": "2026-03-17T15:30:00.000000000Z",
+ "data": {
+ "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "type": "virtual",
+ "status": "blocked",
+ "last4": "4321",
+ "createdAt": "2026-03-17T14:00:00.000000000Z"
+ }
+}
+```
+
+
+### 19. Card.unblocked
+
+Triggered when a card is unblocked and restored to active status.
+
+
+```typescript card.unblocked
+{
+ "id": "evt_e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6",
+ "type": "card.unblocked",
+ "createdAt": "2026-03-17T16:00:00.000000000Z",
+ "data": {
+ "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "type": "virtual",
+ "status": "unblocked",
+ "last4": "4321",
+ "createdAt": "2026-03-17T14:00:00.000000000Z"
+ }
+}
+```
+
+
+### 20. Card.canceled
+
+Triggered when a card is permanently canceled.
+
+
+```typescript card.canceled
+{
+ "id": "evt_f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7",
+ "type": "card.canceled",
+ "createdAt": "2026-03-17T16:30:00.000000000Z",
+ "data": {
+ "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
+ "accountId": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
+ "type": "virtual",
+ "status": "canceled",
+ "last4": "4321",
+ "createdAt": "2026-03-17T14:00:00.000000000Z"
+ }
+}
+```
+
+
+## Card Transaction Events
+
+The following table shows all card transaction event types and when they are triggered:
+
+| Event Type | When It Fires | Pismo Category |
+| ------------------------------------------------ | ---------------------------------------------------- | ----------------------------------------------------------- |
+| `card.transaction.created` | New debit authorization (purchase, withdrawal, etc.) | AUTHORIZATION (debit processing codes) |
+| `card.transaction.refund` | Credit voucher authorization (refund to cardholder) | AUTHORIZATION (credit processing codes: 20, 203100, PSM007) |
+| `card.transaction.declined` | Authorization denied by Pismo | DECLINED |
+| `card.transaction.cleared` | Transaction settled/cleared (B2 confirmation) | CONFIRMATION, AIRPORT_TAX, INSTALLMENT |
+| `card.transaction.reversed` | Full cancellation of an authorization | CANCELLATION |
+| `card.transaction.replacement` | Amount adjustment on a pending authorization | REPLACEMENT |
+| `card.transaction.incremental` | Additional authorization amount added | INCREMENTAL |
+| `card.transaction.partial_cancellation` | Partial reversal of an authorization | PARTIAL_CANCELLATION |
+| `card.transaction.cancellation_reversal` | Undo of a previous cancellation | CANCELLATION_REVERSAL |
+| `card.transaction.reversal_partial_cancellation` | Undo of a previous partial cancellation | REVERSAL_PARTIAL_CANCELLATION |
+
+### 21. Card.transaction.created
+
+Triggered when a new debit authorization occurs (purchase, withdrawal, etc.).
+
+
+```typescript card.transaction.created
+{
+ "id": "evt_8a3c1d4f2b6e9870c2a5b4d6e8f0a1c3",
+ "type": "card.transaction.declined",
+ "createdAt": "2026-04-24T11:17:44.082000000Z",
+ "data": {
+ "id": "f1c84a96-3d05-4b6b-9f1a-b2e7c5d8a012",
+ "accountId": "12c4a7e2-7a91-4f4f-9e76-1c9e1c2a2b18",
+ "cardId": "8a3b2c91-4d7e-49ab-bf25-ef019a4e6b20",
+ "status": "declined",
+ "amount": "20",
+ "currency": "EUR",
+ "decimals": 2,
+ "originalAmount": "20",
+ "originalCurrency": "USD",
+ "originalDecimals": 2,
+ "isCredit": false,
+ "createdAt": "2026-04-24T11:17:43.000000000Z",
+ "updatedAt": "2026-04-24T11:17:43.000000000Z",
+ "description": "Kindle Svcs 888-802-3080 US",
+ "authorizationId": 717,
+ "authorizationCode": "XZ0COI",
+ "merchant": {
+ "name": "Kindle Svcs",
+ "city": "888-802-3080",
+ "country": "US",
+ "categoryCode": "5818"
+ },
+ "entryMode": "0100",
+ "country": null,
+ "billing": {
+ "billingAmount": "20",
+ "billingCurrency": {
+ "symbol": "€",
+ "code": "EUR",
+ "decimals": 2,
+ "name": "Euro"
+ }
+ },
+ "transactionCurrency": {
+ "symbol": "$",
+ "code": "USD",
+ "decimals": 2,
+ "name": "US Dollar"
+ },
+ "cardToken": "8a3b2c91-4d7e-49ab-bf25-ef019a4e6b20",
+ "wallet": {
+ "provider": "apple_pay",
+ "deviceName": "aVBhZCAoMyk.",
+ "deviceType": "TABLET",
+ "deviceBrand": null,
+ "deviceModel": null
+ },
+ "clearedAt": null,
+ "isPending": false,
+ "kind": "payment",
+ "transactionType": "0100",
+ "transactions": [],
+ "declineReason": {
+ "code": "810",
+ "message": "Insufficient balance"
+ }
+ }
+}
+```
+
diff --git a/guides/webhooks/webhook.mdx b/guides/webhooks/webhook.mdx
new file mode 100644
index 0000000..1d0036f
--- /dev/null
+++ b/guides/webhooks/webhook.mdx
@@ -0,0 +1,90 @@
+---
+title: "Introduction to Webhooks"
+description: "Step-by-step guide to set up and implement webhooks in your application with Partner Dashboard"
+---
+
+Webhooks provide real-time notifications when events happen in the Gnosis Pay system. Rather than constantly polling our APIs for updates, you can configure webhook endpoints to receive instant notifications about card transactions, account status and balances, kyc statuses, and more.
+
+
+## Enable Webhooks
+
+To implement webhooks in your application, follow these essential steps:
+
+
+
+Create a publicly accessible HTTP endpoint in your application that can receive POST requests. This endpoint must be available over HTTPS and return a 2xx status code to acknowledge receipt of webhook events.
+
+
+Your webhook endpoint must be publicly accessible. For local development, use tools like [ngrok](https://ngrok.com/) to expose your local server.
+
+
+
+
+Configure your webhook endpoint URL directly through the **Partners Dashboard**. Provide the complete HTTPS URL where you want to receive webhook notifications.
+
+
+
+ ```
+ https://partner-dashboard.sandbox.gnosispay.com/
+ ```
+
+
+
+
+
+
+When events happen in the Gnosis Pay system, we'll send HTTP POST requests to your webhook endpoint with event data and cryptographic signatures.
+
+All webhooks include cryptographic signatures using **Ed25519 asymmetric cryptography**:
+
+- **`X-Webhook-Timestamp`**: Unix timestamp when the webhook was sent
+- **`X-Webhook-Signature`**: Base64-encoded Ed25519 signature
+
+
+ **Always verify webhook signatures** before processing events. This ensures
+ the webhook originated from Gnosis Pay and hasn't been tampered with.
+
+
+
+
+
+
+Extract the `Type` and `data` fields from the webhook payload. The `Type` identifies what happened (e.g., `user.created`, `kyc.status.changed`), while `data` contains the complete entity information.
+
+```json
+{
+ "id": "evt_a1b2c3d4e5f6...",
+ "type": "account.balance.changed",
+ "createdAt": "2026-03-04T12:00:00.000Z",
+ "data": {
+ "accountId": "550e8400-e29b-41d4-a716-446655440000",
+ "balances": [
+ ]
+ ....
+ }
+}
+```
+
+Handle each event type appropriately in your application. Since we send complete entity data, you typically won't need additional API calls to get the full context.
+
+
+Process events idempotently to handle potential duplicates, and implement proper error handling and logging for monitoring.
+
+
+
+**Retry Policy**:
+- **Max attempts**: 5 retries
+- **Timeout**: 30 seconds per request
+- **4xx responses**: Treated as permanent failures (no retry) - endpoint misconfiguration
+- **5xx/connection errors**: Retried up to maximum attempts
+- **Config changes**: Jobs cancelled if webhook config is paused/deleted during delivery
+
+If your webhook endpoint returns a non-2xx status code, we'll retry delivery according to these rules.
+
+
+
+ **Timeout**: Your webhook endpoint must respond within 30 seconds. Requests that exceed this timeout are considered failed and will trigger our retry mechanism.
+
+
+
+
diff --git a/index.mdx b/index.mdx
index 723fa91..327a9ef 100644
--- a/index.mdx
+++ b/index.mdx
@@ -1,71 +1,85 @@
---
-title: "Introduction"
-description: "Welcome to GnosisPay Documentation"
+title: "Gnosis Pay"
+description: "White-label infrastructure for instant card issuance, fiat rails, and multi-currency accounts"
+mode: "custom"
---
-This documentation is designed to help developers and businesses leverage our APIs
-to enable seamless card issuance, management, and user experiences for their customers.
+
-With Gnosis Pay, you can offer your users a simple way to interact with crypto payments in the real world while enjoying
-the security of self-custodial wallets. By following the steps in this guide, you can ship stablecoin program for users and allow them to spend crypto.
+
+
+
-
- Get a Gnosis Pay account today by signing in to the Gnosis Pay webapp and start spending crypto in the real world.
-
+
+
+ Ship stablecoin card programs in minutes
+
+
+ White-label infrastructure for instant card issuance, fiat rails, and multi-currency accounts.
+
-Gnosis Pay's first product is Gnosis Card: a stablecoin based visa debit card,
-enabling users to spend their digital assets in the traditional economy using the Gnosis Pay network.
-
-
- Easily spend crypto like you spend cash.
-
-
- >
- Accepted at 80+ million Visa merchants worldwide.
+
+
+ Deploy Gnosis Pay infra across different blockchains. Live on Celo and Gnosis Chain.
-
-
- Take control of your money through your SAFE account. You own your keys, you own your crypto.
+
+ Enable your ecosystem's stablecoin as a spending currency, fully on-chain with native support.
+
+
+ Accept KYC already verified by trusted partners, no need of double KYC verification process.
+
+
+ Reversals are processed instantly as the message is received by network.
+
+
+ Setup multi-currency accounts in EUR, USD, and GBP available.
+
+ Live across Brazil, the EU, UK, Cyprus, Colombia, the Philippines, Mexico, Japan, Indonesia, Thailand, and Singapore and expanding.
+
+
-
- Add savings and investment features by connecting to DeFi protocols through plug-and-play integrations.
-
+
-
- Earn up to 5% cashback on eligible transactions based on the amount of GNO you hold in your wallet.
-
+
-
- On and Off ramp integrations are available with our integrated ramp partners such as Noah, Monerium and Avenia.
-
-
+
+
diff --git a/integration-model.mdx b/integration-model.mdx
deleted file mode 100644
index ff586b0..0000000
--- a/integration-model.mdx
+++ /dev/null
@@ -1,118 +0,0 @@
----
-title: "Integration models : Permissionless vs Partnerships"
-description: "Gnosis Pay offers two ways of integrating Gnosis Pay APIs. Whether you’re building as a developer or looking to launch a whitelisted branded solution, Gnosis Pay is designed to be flexible and accessible for all developers and businesses."
----
-## Integration Models: Permissionless vs Partnerships
-
-Gnosis Pay offers two ways to get started:
-
-1. Permissionless Integration
-2. Partnership Integration
-
----
-## 1. Permissionless Integration (Free Plan Only)
-
-Developers can start building with our APIs right away—no need to contact us or go through an approval process. This lets you quickly enable crypto payments, card issuance, and account features for your users.
-
-
-
-
-This integration requires no special credentials. Simply authenticate with our APIs using SIWE (Sign-In with Ethereum) to receive a JWT token and start building.
-
-
-**Who it's for:** Developers or small teams who want to explore the APIs, prototype, or run very lightweight programs.
-
-
-
- - ✅ Make API calls immediately — no API keys, approvals, or contracts
- - ✅ Issue and manage Gnosis-branded cards for testing and early users
- - ✅ Experiment with basic functionality (card issuance, transactions, balance queries)
-
-
-
- - ❌ Attribute card activity back to your business (no webhooks, no tracking)
- - ❌ Display sensitive card details (requires Partner Secure Element)
- - ❌ Launch a branded card program at scale
-
-
-
-
-Once you want to connect card activity to your app/business or expose sensitive card details, you'll need to switch into Partnership mode.
-
-
----
-
-## 2. Partnership Integration (Free, Startup, and Enterprise)
-
-If your company is interested in deeper collaboration—such as branded cards, custom user experiences, fee rebates, or co-marketing opportunities — you can sign up through our [Partners Dashboard](https://partners.gnosispay.com/).
-
-
-**Domain Whitelisting Required**: During partner signup, you must provide all production and staging domains where your application will be hosted. These domains are whitelisted for SIWE (Sign-In with Ethereum) authentication and CORS.
-
-- **localhost**: Automatically allowed for local development (e.g., `localhost:3000`)
-- **Production/Staging**: All non-localhost domains must be registered during signup
-- Applications running on non-whitelisted domains will face authentication failures
-
-
-
-
-
-
-**Who it's for:** Any partner ready to move beyond experimentation and operate a live program.
-
-
-
- - **Partner ID** → Required for webhooks, attribution, and tracking
-
- - **App ID** → Required for Partner Secure Element (PSE) access
-
-
-
- - Branded cards and custom experiences
- - Multi-market support
- - BIN sponsorship
- - Compliance oversight
-
-
-
-
-
- Direct access to Gnosis Pay team for technical guidance and business support.
-
-
-
- Complete integration into your systems with webhooks and analytics.
-
-
-
-**Mandatory for:** Startup and Enterprise plans, but also available to Free Plan partners who want to extend beyond pure experimentation.
-
-
-## **Getting Your PartnerID and APP_ID**
-
-Through our self-service [Partners Dashboard](https://partners.gnosispay.com/), partners can:
-- **PartnerID**: A unique identifier for partner organization within the Gnosis Pay ecosystem, enabling us to track user acquisition and attribute activity to integration.
-
-- **APP_ID**: An application-specific identifier that allows partners to authenticate with the PSE (Partner Secure Elements) and establish secure mTLS connection authentication between partner and Gnosis Pay.
-
-
- To get your PartnerID and APP_ID through the Partners Dashboard:
- 1. Sign up at [partners.gnosispay.com](https://partners.gnosispay.com/)
- 2. Include your company details and app domains (required for CORS whitelisting)
- 3. Get your PartnerID and APP_ID instantly upon registration
- 4. Handle PSE integration setup, CSR signature, and webhook configuration directly through the dashboard
-
- **Critical**: You must include all your production and staging domains during signup. While localhost is automatically allowed for development, all other domains must be whitelisted for both CORS and SIWE authentication. Missing domains will cause authentication failures and API access issues.
-
diff --git a/migration/migration-overview.mdx b/migration/migration-overview.mdx
new file mode 100644
index 0000000..a0fd651
--- /dev/null
+++ b/migration/migration-overview.mdx
@@ -0,0 +1,23 @@
+---
+title: "Migrating to new Gnosis Pay APIs"
+description: "Overview of the differences between Gnosis Pay's old and new infrastructure, only applicable to old Partners integrating new APIs"
+---
+
+This page compares Gnosis Pay's old API infrastructure against the current architecture, to help partners understand what changed and why, particularly around authentication, ownership, and other flows.
+
+## Feature Comparison
+
+| Feature | Old API | New API |
+|---|---|---|
+| **SIWE Authentication** | Long-lived access token (24h) | Access token (15 min validity) and refresh token model (7 days validity) with rotation support |
+| **Reversals** | Processed after 1 business day | Instantly processed right after the clearing message |
+| **KYC Verification** | Dependent on Gnosis Pay to complete KYC; Gnosis Pay shares KYC results with partners | KYC can be performed by partners and shared with Gnosis Pay |
+| **Safe Deployment** | Dedicated Safe deployment endpoint | Single `/account` endpoint handling provisioning + creation |
+| **Token Management** | Limited support for single token/currency | Multi-currency support with different balance states |
+| **Account Balances** | Spendable, non-spendable, and total balance | Detailed breakdown: spendable, authorized holds, non-spendable, processing deposits |
+| **Withdrawals** | Subject to delay module | Instant, bypassing the delay module |
+| **Daily Onchain Spending Limits** | Set by user, requires an onchain signature | Hardcoded at $20,000 daily limit (2x card limit buffer), no signature required |
+| **Delay Module Configuration** | 3-minute delay, 30-minute expiration | 25-hour delay, 31-hour expiration (discourages usage) |
+| **Transactions** | Separated by card transaction and onchain transaction; onchain transactions only available via RPC | Unified account-statement endpoint showing deposits, withdrawals, and card transactions |
+| **Owner Address** | Multiple SIWE-authenticated addresses could be added alongside the Safe owner | A single owner address, set at account creation, cannot be changed, and no other SIWE addresses can be added |
+| **Pre-Authorization Holds**| Not allowed in old infrastructure | Pre-authorization holds allowed, users can use it for gas stations or car rentals etc. |
diff --git a/on-off-ramps/iban-integration.mdx b/on-off-ramps/iban-integration.mdx
deleted file mode 100644
index 79a1ecf..0000000
--- a/on-off-ramps/iban-integration.mdx
+++ /dev/null
@@ -1,151 +0,0 @@
----
-title: IBAN Integration
-description: IBAN cash-in to the Gnosis Pay Account via Monerium
----
-
-We offer IBAN cash-in to the Gnosis Pay Account via Monerium for users in Europe (EU) and Switzerland.
-
-Monerium's IBAN integration enables direct connection between the owner of the GP Safe (which is the authenticated account address for SIWE) and Monerium.
-
-- By calling the integrations endpoint (see below), it shares the user's KYC with Monerium.
-
-- You can use [Monerium API](https://monerium.dev/api-docs/v2) to authenticate with SIWE and perform actions enabled by the Monerium API
-
-- This API operates independently of the GP Safe and does not involve signatures on the delay module.
-
-
-
-## Check Availability
-
-[First you need to check if the user is eligible to have an IBAN](/api-reference/iban/check-iban-availability):
-
-```bash cURL
-curl -X GET /api/v1/ibans/available
-```
-
-If you receive a `"available": false`, the flow ends here.
-
-
-Requirements that the Gnosis Pay user must have:
-- Valid date of birth
-- An active EURe Safe Account
-- KYC verified and approved
-- Residency in a supported country
-- First and last name defined (or name)
-- Valid location fields filled in (address1, postalCode, city and country, none of these fields can be missing)
-- Nationality from a supported country ([see allowed and restricted nationalities](https://help.gnosispay.com/hc/en-us/articles/39558629298708-Eligible-Nationalities-for-the-Gnosis-Pay-IBAN-Feature))
-
-
-## Enabling the IBAN Integration
-
-
-
-
-
-Monerium requires a specific message to be signed by the user's wallet to prove the ownership of the wallet.
-[Use this endpoint to get the exact message that needs to be signed](/api-reference/iban/get-the-message-that-needs-to-be-signed-for-iban-activation):
-
-```bash cURL
-curl -X GET /api/v1/ibans/signing-message
-```
-
-
-We cannot request new IBANs nor transfer existing IBANs until the message signature is completed. This signature is a mandatory requirement from Monerium to verify ownership of the address.
-
-
-
-
-
-
-Use the message string returned from [step 1](#signing-the-monerium-message) to generate a signature with the user's wallet.
-
-To request signature from the user's wallet, you can follow this [demo signature implementation](#message-signing-example-with-viem).
-
-
-
-
-
-[Make a POST request to this endpoint to request IBAN integration for Gnosis Pay user](https://docs.gnosispay.com/api-reference/iban/create-a-new-monerium-integration):
-
-```bash cURL
-curl --request POST \
- --url https://api.gnosispay.com/api/v1/integrations/monerium \
- --header 'Authorization: Bearer ' \
- --header 'Content-Type: application/json' \
- --data '{
- "signature": ""
-}'
-```
-If the request is successful, you will receive a response with the IBAN details.
-This endpoint effectively:
-- shares the user's KYC info with Monerium
-- creates an IBAN linked to the user's account
-
-
-Monerium only allows the user to have one single account with them. If a Monerium account **already exists**, then there is **no need** to call this endpoint. In such cases, users can grant access to their existing Monerium account using the Monerium API directly.
-
-
-
-
-
-
-To retrieve IBAN details including the IBAN number, BIC code, status, and connected account address, you can get them with the `bankingDetails` field from:
-```bash cURL
-curl -X GET /api/v1/user
-```
-
-
-
-
-
-Follow the guide available at https://monerium.dev/docs/welcome
-To authenticate with their API, you can then use the method described in https://monerium.dev/api-docs/v2#tag/auth *using the SIWE* flow.
-
-Once authenticated, you can manage IBANs, create instructions to transfer funds from one account to another, etc.
-
-
-
-
-
-For detailed error status codes and examples, please refer to the API Reference documentation [here for IBAN integration](https://docs.gnosispay.com/api-reference/iban/create-a-new-monerium-integration).
-
-The Gnosis Pay API serves as a wrapper for Monerium IBAN integration. Therefore, any issues related to Monerium integration should be addressed directly between your products and Monerium.
-
-
-## Message Signing Example with Viem
-
-This is an example script to generate a signature from an EOA wallet address that is an owner of GP Safe and will be linked to Monerium profile.
-
-### Example Usage
-
-```typescript
-import { createWalletClient, http } from 'viem';
-import { gnosis } from 'viem/chains';
-import { privateKeyToAccount } from 'viem/accounts';
-
-// Initialize wallet client with private key
-const account = privateKeyToAccount('0x...' as `0x${string}`);
-const walletClient = createWalletClient({
- account,
- chain: gnosis,
- transport: http()
-});
-
-// Get the message to sign from the API
-const message = "I hereby declare that I am the address owner.";
-
-// Sign the message directly with EOA
-const signature = await walletClient.signMessage({
- message
-});
-
-console.log('Signature:', signature);
-console.log('Signer address:', account.address);
-```
-
-
-Note:
-- The message can be fetched from the API using `GET /api/v1/ibans/signing-message`
-- The signature can be submitted to prove ownership
-- Make sure to use the correct chainId (100 for Gnosis Chain)
-
diff --git a/on-off-ramps/index.mdx b/on-off-ramps/index.mdx
deleted file mode 100644
index b346453..0000000
--- a/on-off-ramps/index.mdx
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: "On/Off Ramp Integrations"
-description: "Complete guide to fiat-to-crypto conversions with Gnosis Pay's integrated ramp partners"
----
-
-# On/Off Ramp Integrations
-
-Convert between fiat currencies and stablecoins seamlessly with Gnosis Pay's integrated ramp partners.
-
-
-**No Double KYC Required**
-
-On/Off ramp integrations don't require users to complete another KYC process with Gnosis Pay - they can use their existing verification from our integrated partners.
-
-
-
-**Important Partnership Requirements**
-
-Please be aware of the following integration requirements:
-
--**Direct Provider Relationships**: The wallet/platform must establish a direct contractual relationship with the ramp provider (e.g., Noah, Monerium, Avenia) and integrate directly with their APIs. Gnosis Pay will only facilitate the KYC process by sharing the KYC collected data via Sumsub.
-
-- **Mandatory usage of Sumsub**: It is mandatory to use Sumsub instance to avail these integrations.
-
-
-For detailed KYC sharing implementation, please refer to our [KYC Sharing Integration Guide](on-off-ramps/kyc-sharing).
-
-
-## Available Integrations
-
-
-
- **EUR to EUR.e via Monerium**
-
- Full SEPA integration with IBAN support for European users.
-
-
-
- **USD to USDC.e via Noah**
-
- Fast and reliable USD conversion for North American markets.
-
-
-
- **BRL to BRLA via Avenia**
-
- Brazilian Real support specifically designed for LatAm markets.
-
-
diff --git a/on-off-ramps/kyc-sharing.mdx b/on-off-ramps/kyc-sharing.mdx
deleted file mode 100644
index bc974df..0000000
--- a/on-off-ramps/kyc-sharing.mdx
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: KYC sharing for GP Partners
-description: This guide explains how to share existing Gnosis Pay KYC data with GP Partners using Sumsub's reusable token system.
----
-## KYC Sharing Partners
-
-KYC Sharing allows users who have already completed verification with Gnosis Pay to re-use their KYC data with partner platforms, eliminating the need for duplicate verification processes. KYC sharing is currently only available through **Sumsub** and requires a formal contract between three parties: Gnosis Pay, Sumsub, and partner platform.
-
-
-**Important Limitations**
-
-- **One-Way Sharing**: We only support **Gnosis Pay → Partner Platform** sharing. KYC data cannot be shared from partner platforms back to Gnosis Pay.
-- **Approval Not Guaranteed**: Since every company has different KYC requirements and risk policies, some Gnosis Pay approved KYCs may be rejected at the destination platform.
-
-
-## How to get reusable token for KYC Sharing Partners
-
-The following partners currently support KYC data sharing:
-
-| Partner | Sumsub Client ID |
-|---------|------------------|
-| Noah | `noah.com_112876` |
-| BRLA | `brla.digital_101963` |
-
-
-
- For existing partners available for KYC sharing, use one of the Client IDs from the table above. For partners not listed in the table, contact the Partner team to obtain their SumSub Client ID.
-
-
-
-
- Once the Sumsub Client ID has been obtained, generate a reusable token using the Gnosis Pay API.
-
- Share this token to Sumsub's API to re-use the KYC and get data for users. To learn more about how to use Sumsub's API, visit their documentation [here](https://docs.sumsub.com/docs/reusable-kyc).
-