> For the complete documentation index, see [llms.txt](https://docs.fonbnk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fonbnk.com/widget-integration/skipping-screens.md).

# Skipping screens

Pre-fill what you already know and drop the widget screens you do not need.

### The full journey

The two directions do not have the same screens, and the on-ramp has one the off-ramp does not.

**On-ramp** — the user buys crypto:

1. **Amount** (`/`) — pick a country, a payment channel, a cryptocurrency and an amount.
2. **Wallet** (`/wallet`) — connect via MetaMask, WalletConnect or another supported option, or paste an address.
3. **Login** (`/auth`, then `/otp`) — enter an email and the one-time code sent to it.
4. **KYC** (`/onramp/kyc`) — only when the order needs it.
5. **Order** (`/swap`) — review the order, fill in whatever the payment channel needs (phone number, bank, and so on), and create it.
6. **Pay** — the transfer instructions, then confirm.
7. **Status** (`/swap-status`) — the crypto lands once the payment clears.

**Off-ramp** — the user sells crypto:

1. **Amount** (`/offramp`)
2. **Login** (`/offramp/auth`, then `/offramp/otp`)
3. **KYC** (`/offramp/kyc`) — only where the country requires off-ramp KYC.
4. **Order** (`/offramp/create`)
5. **Pay** (`/offramp/pay`)
6. **Status** (`/offramp/status`)

There is **no Wallet screen on the off-ramp** — the user sends the crypto from wherever they hold it, so there is nothing to connect. Every path below is the on-ramp one unless it says otherwise.

Each screen can be skipped by supplying what it would have asked for. Skip from the front: you cannot skip the Wallet screen while still showing Amount.

{% hint style="warning" %}
**Use the sandbox host while you build.** The widget is `https://sandbox-pay.fonbnk.com` in sandbox and `https://pay.fonbnk.com` in production, with separate credentials and separate users — the URLs on this page use the sandbox host. In production you must be a verified merchant to sign URLs or predefine a wallet address.
{% endhint %}

### Skipping the Amount page

Supply everything the amount screen collects and open `/wallet` directly:

* `countryIsoCode`
* `paymentChannel`
* `network`
* `asset`
* `currency`
* `amount`
* `source` and `signature`

The `signature` is a JWT (HS256) signed with your "URL signature secret" from the merchant dashboard. It proves the link came from you. For testing you can generate one at <https://jwt.io/>.

```typescript
import * as jsonwebtoken from 'jsonwebtoken';
import { v4 as uuid } from 'uuid';

const token = jsonwebtoken.sign(
    {
      uid: uuid(),
    },
    YOUR_SIGNATURE_SECRET,
    {
      algorithm: 'HS256',
    },
 );
```

A Nigerian bank order for 2 CELO USDT:

{% code overflow="wrap" %}

```
https://sandbox-pay.fonbnk.com/wallet?source=xsdf_2&signature=...&network=CELO&asset=USDT&amount=2&currency=crypto&paymentChannel=bank&countryIsoCode=NG
```

{% endcode %}

### Skipping the Wallet page

On-ramp only. Add `address` — the user's wallet — and open `/auth` instead:

{% code overflow="wrap" %}

```
https://sandbox-pay.fonbnk.com/auth?source=xsdf_2&signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiJ3ZmVuZmVrbndmZWtud2Zua2plMzIyMjEzMTIzMTIzMTIzIn0.bkFNaPYEeLNoUv7RhCWWROdbsGgJCQQp9Xpk628EoJA&network=CELO&asset=USDT&amount=2&currency=crypto&paymentChannel=bank&countryIsoCode=NG&address=0x91b0a33dbcb10f8331eD3627B94e5a9B1591269f
```

{% endcode %}

### Skipping the Login page

Log the user in on their behalf and pass their tokens. Call [Generate user auth tokens](/server-to-server/api-endpoints/generate-user-auth-tokens.md) with their email and country — see [Signing requests](/server-to-server/signing-requests.md) for how to sign the call:

```json
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

{% hint style="warning" %}
This endpoint is disabled for merchants by default. Contact support to have it enabled for your account.
{% endhint %}

Pass them as `at` and `rt` — **both, or neither**: a lone `at` is ignored and the user is asked to log in anyway. Then open `/swap` (`/offramp/create` on the off-ramp):

{% code overflow="wrap" %}

```
https://sandbox-pay.fonbnk.com/swap?source=xsdf_2&signature=...&network=CELO&asset=USDT&amount=2&currency=crypto&paymentChannel=bank&countryIsoCode=NG&address=0x91b0a33dbcb10f8331eD3627B94e5a9B1591269f&at=...&rt=...
```

{% endcode %}

### KYC

KYC cannot be skipped from the URL. It can only be switched off for your whole account, and only if you already run KYC on your own users. Contact support to arrange it. See [KYC](/kyc.md).

It can, however, be **started** from a URL, on its own and with no order. [Get user KYC state](/server-to-server/api-endpoints/get-user-kyc-state.md) answers `kycUrls`, one ready link per tier. Send the user the link and they verify on our pages: the email you named is prefilled and locked, they enter the one-time code, and the document form for that tier opens. You read the result the same way you always do, by polling `passedKycType` or by taking the `kyc` webhook.

That is the opposite of the skips above. Here you are not removing a screen from an order, you are opening the KYC screen with nothing else around it. The recipe is on [KYC flow](/server-to-server/kyc-flow.md).

### Skipping the Order page

Two more parameters, both derived from a quote:

* `quoteId`
* `requiredFields`

Call [Create quote](/server-to-server/api-endpoints/create-quote.md). Its response carries `deposit.fieldsToCreateOrder` and `payout.fieldsToCreateOrder` — collect every field marked `required: true` from **both**, put them in one flat object, then stringify and URL-encode it:

```typescript
const values = {
  phoneNumber: "2348012345678",
  bankCode: "1",
  bankAccountNumber: "1234567890",
  blockchainWalletAddress: "0x91b0a33dbcb10f8331eD3627B94e5a9B1591269f",
};
const encoded = encodeURIComponent(JSON.stringify(values));
```

Send everything to `/auto-order`, and include `flow` — that page serves both directions, so it has to be told which one:

{% code overflow="wrap" %}

```
https://sandbox-pay.fonbnk.com/auto-order?source=xsdf_2&signature=...&flow=onramp&network=CELO&asset=USDT&amount=2&currency=crypto&paymentChannel=bank&countryIsoCode=NG&address=0x91b0a33dbcb10f8331eD3627B94e5a9B1591269f&at=...&rt=...&quoteId=6878df150d6289ffdedcd6f4&requiredFields=%7B%22phoneNumber%22%3A%222348012345678%22%2C%22bankCode%22%3A%221%22%2C%22bankAccountNumber%22%3A%221234567890%22%2C%22blockchainWalletAddress%22%3A%220x91b0a33dbcb10f8331eD3627B94e5a9B1591269f%22%7D
```

{% endcode %}

That `requiredFields` value is the four fields above, encoded. The order is created as the page loads and the user lands straight on the transfer instructions.

{% hint style="warning" %}
**Keep `%` out of the values.** The widget decodes `requiredFields` once on the way in and once again before parsing it, so a value that contains a literal percent sign — a bank account name like `50% Holdings`, say — fails to decode. The failure is silent: the page catches it and drops the user on the Amount screen with every skip discarded. Everything the payment channels ask for today is digits or an address, so this bites rarely; if you must pass free text, check it first.
{% endhint %}

### The recommended way

Use `/auto-order` for all of the above. Give it everything you know, always with `flow`, and it works out which screen the user still needs.

It checks in this order, and sends the user to the first thing that is missing:

1. `network` and `asset` — missing, and the user goes to Amount.
2. A quote — it creates one (or uses your `quoteId`); if that fails, Amount.
3. **Login** — no valid `at`/`rt`, and the user goes to Login, even on the on-ramp where the Wallet screen comes first on screen.
4. `address` — on-ramp only; missing, and the user goes to Wallet.
5. KYC — required, and the user goes to the KYC screen.
6. Otherwise the order is created and the user lands on the transfer instructions.

{% hint style="warning" %}
**`flow` is not optional in practice.** If it is missing or is not exactly `onramp` or `offramp`, `/auto-order` throws internally, catches it, and forwards the user to the **on-ramp Amount screen** — discarding every skip you passed. A user who should have landed on transfer instructions starts from scratch instead, in the wrong direction. Send it, lower case, every time.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.fonbnk.com/widget-integration/skipping-screens.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
