# LLM On Ramp

````
# Onramp Documentation

## Table of Contents

* [Session-Based Integration](#session-based-integration)
* [Limiting Assets in the Widget](#limiting-assets-in-the-widget)
* [The extra Object](#the-extra-object)
* [Data Prefill](#data-prefill)
* [Listeners Object](#listeners-object)
* [Widget Display Methods](#widget-display-methods)
* [Converter API Reference](#converter-api-reference)
* [Error Codes Reference](#error-codes-reference)
* [Supported Coins and Blockchains](#supported-coins-and-blockchains)

---

## Session-Based Integration

Wert’s fiat onramp is initialised through a session-based integration flow, designed to give you full control over the transaction experience.

This flow consists of two simple steps:

1. Create a session via API, including all necessary transaction and user details
2. Initialise the widget using the session_id returned from the API

This allows you to tailor how the onramp behaves — from fully user-driven to fully preconfigured — depending on your use case.

### 1. Create Session

> **Note:** To start the widget, you must create a new session via our Partner API.

#### Endpoints

| Environment | URL | Method |
| --- | --- | --- |
| `Sandbox` | `https://partner-sandbox.wert.io/api/external/hpp/create-session` | `POST` |
| `Production` | `https://partner.wert.io/api/external/hpp/create-session` | `POST` |

#### Authentication

To authenticate your requests, include your API key in the HTTP header of every request.

| Header Key | Value |
| --- | --- |
| `X-Api-Key` | `your-unique-api-key` |

> **Warning: Your API key carries many privileges, so keep it secure.**  
> Your API key is provided exclusively by Wert during onboarding. **Store it safely in your backend.**  
> Never share your key. If you suspect a compromise, contact us immediately to issue a new one.  
> **Note:** Sandbox and Production keys are **unique** to their respective environments and are not interchangeable.

#### Parameters

> **Tip:** `flow_type: simple_full_restrict` ensures all parameters are locked and cannot be edited by users.

| Property | Required | Description | Data Type | Default Value | Possible Values |
| --- | --- | --- | --- | --- | --- |
| `flow_type` | Yes | Determines widget behaviour. **simple**: Users choose. **simple_full_restrict**: Partner-defined options. | string | `simple` | `simple`, `simple_full_restrict` |
| `user_id` | No | The User ID for the associated profile. | string | - | `01KQWHEJNSY` |
| `commodity` | * | Default crypto asset selected. | string | `BTC` | [See docs](https://docs.wert.io/docs/supported-coins-and-blockchains) |
| `commodity_amount` | * | Pre-filled crypto amount. Ignored if `currency_amount` is set. | numeric | - | - |
| `network` | * | Network for the default asset. | string | `bitcoin` | [See docs](https://docs.wert.io/docs/supported-coins-and-blockchains) |
| `wallet_address` | * | User’s wallet address. Validated based on commodity. | string | - | - |
| `currency` | * | Fiat currency. Required if `currency_amount` is used. `EUR` is not available in sandbox. | string | - | `USD`, `EUR` |
| `currency_amount` | * | Pre-filled fiat amount ($1 min / $30 min for BTC). | numeric | - | - |

* **(*) Requirement:** All properties marked with an asterisk are required when `flow_type` is set to `simple_full_restrict`.
* Use either `commodity_amount` or `currency_amount`, but **not both**.

#### Examples

##### simple
```bash
curl -X POST "https://partner-sandbox.wert.io/api/external/hpp/create-session" -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" -d '{
  "flow_type": "simple"
}'
```

##### simple_full_restrict
```bash
curl -X POST "https://partner-sandbox.wert.io/api/external/hpp/create-session" -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" -d '{
  "flow_type": "simple_full_restrict",
  "wallet_address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  "currency": "USD",
  "commodity": "TT",
  "network": "amoy",
  "currency_amount": 100.50
}'
```

In sandbox, please use only USD and [sandbox commodities](https://docs.wert.io/docs/supported-coins-and-blockchains#sandbox).

#### Responses

##### 200 (OK)
```json
{
  "sessionId": "string",
  "requestId": "string"
}
```

##### 400 (Missing required fields)
```json
{
  "message": "Invalid request: wallet_address and either commodity_amount or currency_amount must be specified."
}
```

##### 401 (Unauthorized request)
```json
{
  "message": "Unauthorized: API key is missing or invalid."
}
```

> **Important:** The `sessionId` is valid for 30 seconds after being created and can only be used once.

---

### 2. Initialize the Widget

> **Mandatory Guidelines:**  
> To ensure the security and stability of your integration, please adhere to the following mandatory guidelines:  
>  
> * **Official SDK Only:** Using our [official SDK](https://www.npmjs.com/package/@wert-io/widget-initializer) is the **ONLY** supported method for initializing the widget.  
> * **React Projects:** If you are building with React, please use our [dedicated wrapper](https://www.npmjs.com/package/@wert-io/module-react-component).  
> * **Mobile Integration:** For mobile applications, create a web app utilizing our [SDK](https://www.npmjs.com/package/@wert-io/widget-initializer) and embed the web app within your native app using a WebView or equivalent technology.  
> * **No Direct Redirects:** Opening the widget via a direct redirect link is not supported.  
> * **Reference Implementations:** Check out our [GitHub Integration Examples](https://github.com/wert-io/widget-integration-example/blob/master/src/buy-crypto.ts) for reference implementations.

Once the SDK is installed, you can use the following code snippet to initialize the payment module:

```typescript
// Import the SDK
import WertWidget from '@wert-io/widget-initializer';
import type { Options } from '@wert-io/widget-initializer/types';

// Initialize the payment module
const options: Options = {
  partner_id: 'YourPartnerID',
  session_id: 'SessionID', // session id received from partner.wert.io/api/
  origin: 'https://sandbox.wert.io', // this option needed only in sandbox
};

const wertWidget = new WertWidget(options);

wertWidget.open();

// Further code to handle widget events and interactions
```

---

### Options

Here are the options you can pass to the widget.

#### General Options

| Property | Required | Description | Data Type | Default Value | Possible Values |
| --- | --- | --- | --- | --- | --- |
| `partner_id` | Yes | Provided when you register as a partner. | string | - | - |
| `session_id` | Yes | session_id returned from the API | string | - | - |
| `origin` | In sandbox | Initializes the module in a sandbox/production environment. | string | `https://widget.wert.io` | `https://sandbox.wert.io` |
| `click_id` | No | A unique identifier created by you. Can be used to help you reconcile the order on your side. | string | `click_id` | `uuid_v4()`. Try to avoid using special characters like % or pass them encoded. |
| `phone` | No | User’s phone number in international format (E.164 standard). The ‘+’ is optional. | string | - | `+11014321111` |
| `redirect_url` | No | Includes a button *'Back to {Partner Name}'* (not available in iFrame). Also redirects users from KYC emails. | string | - | `https://origin.us/item_id` |
| `support_url` | No | Used for helping users with failed orders. | string | - | `https://partner.com/support` |
| `listeners` | No | Used to listen to module events and react to them. | object | - | See [listeners object](https://docs.wert.io/docs/listerners-object). |
| `commodities` | No | Stringified JSON array of objects with commodity and network options. | string | By default, all assets are displayed. | See [Limiting assets](https://docs.wert.io/docs/limiting-assets-in-the-widget) |
| `extra` | No | Passing multiple wallet addresses to the widget. | string | - | See [Multiple addresses](https://docs.wert.io/docs/extra-object-fiat-onramp) |
| `payment_method` | No | Pre-selected payment method shown first in the list. | string | `card` | `card`, `apple-pay`, `google-pay`, `sepa`, `cash-app` |
| `payment_method_restriction` | No | If true, shows only the method specified in `payment_method`. | boolean | `false` | `true`, `false` |
| `display_currency` | No | ISO currency code to display approximate estimated amounts. | string | - | `AUD`, `SGD`, `HKD`, `THB`, `MYR`, `VND` |
| `hide_fee_breakdown` | No | Hides fee details for all payment methods and only the fee value is shown. | boolean | `false` | `true`, `false` |

#### Pre-filled User Data

| Property | Required | Description | Data Type | Default Value | Possible Values |
| --- | --- | --- | --- | --- | --- |
| `country_of_residence` | No | User’s country of residence. | string | - | [alpha2](https://www.nationsonline.org/oneworld/country_code_list.htm) code of the country |
| `state_of_residence` | No | User’s state of residence (for USA). | string | - | [alpha2](https://www.iso.org/obp/ui/#iso:code:3166:US) code of the state |
| `date_of_birth` | No | User’s date of birth. | string | - | `DD/MM/YYYY`, `MM/DD/YYYY` (USA) |
| `email` | No | User’s email address. | string | - | `test@test.com` |
| `full_name` | No | The user’s first and last name. | string | - | min 3, max 69 letters; `RegExp(/(\w+\s)\w+/)` |
| `card_country_code` | No | Card billing address country code. | string | - | `US` ([alpha2](https://www.nationsonline.org/oneworld/country_code_list.htm)) |
| `card_city` | No | Card billing address city. | string | - | `Los Angeles` |
| `card_state_code` | No | Card billing address state code (For US). | string | - | `CA` ([alpha2](https://www.iso.org/obp/ui/#iso:code:3166:US)) |
| `card_post_code` | No | Card billing address postal code. | string | - | `12345` |
| `card_street` | No | Card billing address street. | string | - | `Main street 1` |

#### Appearance and Restrictions

| Property | Required | Description | Data Type | Default Value | Possible Values |
| --- | --- | --- | --- | --- | --- |
| `lang` | No | Language of the widget. | string | `en` | See supported languages list below |
| `skip_init_navigation` | No | By default, the module suggests the nearest purchase route. Setting to `true` skips this logic. | boolean | `undefined` | `true` |
| `theme` | No | Module’s theme color. | string | `undefined` | `dark` |
| `brand_color` | No | Custom brand color for primary buttons, tooltips, steppers, tabs, checkboxes, toasts, and pie countdowns. | string | - | `#FF0000` |

**Supported Languages:** `en` (English), `fr` (French), `ja` (Japanese), `es` (Spanish), `ko` (Korean), `zh` (Chinese), `tr` (Turkish), `de` (German), `ka` (Georgian), `th` (Thai)

---

## Limiting Assets in the Widget

By default, all assets are displayed when the widget is loaded. You can, however, limit the available cryptocurrencies to display only one or several in the 'You get' drop-down list.

1. **Default view with all assets:**  
   ![Default view with all assets](https://files.readme.io/91a4335-Untitled.gif)

2. **Displaying one asset (useful for single-currency wallets):**  
   ![Displaying one asset](https://files.readme.io/a4186b4-Untitled.png)

Pass the following data to load the Widget with a single cryptocurrency:

```javascript
const wertWidget = new WertWidget({
  // ... other options ...
  commodity: "XTZ",
  network: "tezos",
  commodities: JSON.stringify([
    {
      commodity: "XTZ",
      network: "tezos",
    },
  ]),
});
```

3. **Displaying several commodities:**  
   ![Displaying several commodities](https://files.readme.io/74dc32e-Untitled_1.gif)

In order to do so, pass the following data to Wert upon initialization:

```javascript
const wertWidget = new WertWidget({
  // ... other options ...
  commodity: "BTC",
  network: "bitcoin",
  commodities: JSON.stringify([
    {
      commodity: "BTC",
      network: "bitcoin",
    },
    {
      commodity: "ETH",
      network: "ethereum",
    },
  ]),
});
```

Make sure to pass the correct `commodity` and `network` options for this feature to work. You can find them in the [List of supported coins and blockchains](https://docs.wert.io/docs/supported-coins-and-blockchains).

---

## The extra Object

The `extra` object can pass multiple wallets to the widget so the customer can switch between cryptocurrencies during the purchase without manually entering a different wallet address.

When passing wallet addresses in the `extra` object, please keep in mind that:
* Users can always edit the pre-filled addresses.
* Addresses will remain pre-filled if the user switches between cryptocurrencies.
* If you provide addresses for the main cryptocurrency in both the `address` option and the `extra` object, the one in `address` will be pre-filled.
* The `extra` object only functions with [our SDK](https://www.npmjs.com/package/@wert-io/widget-initializer).

Please ensure you pass the correct values in `commodities` and `wallets`. You can find `commodity` values in [Supported Coins and Blockchains](https://docs.wert.io/docs/supported-coins-and-blockchains).

### Wallet Object Structure

You can define an array of default wallets that will be pre-filled when the user switches between cryptocurrencies.

| Property | Type | Description |
| --- | --- | --- |
| `name` | string | Example: `ETH`, refer to [supported currencies](https://docs.wert.io/docs/supported-coins-and-blockchains). |
| `network` | string | Example: `ethereum`, refer to [supported currencies](https://docs.wert.io/docs/supported-coins-and-blockchains). |
| `address` | string | The user's wallet address. Non-valid addresses will be ignored. |

`extra` object structure:

```javascript
extra: {
  item_info: Object,
  wallets: Array,
}
```

### Examples

#### 1. Single Wallet Address
You can provide the required crypto asset and the user's address if it's a single-wallet address. The widget will load with the provided address:

![Single wallet address example](https://files.readme.io/b1c07b0-1_Example.png)

```javascript
const wertWidget = new WertWidget({
  // ... other properties
  commodity: "XTZ",
  network: "tezos",
  address: "tz1LjQKVfHCCCYm8DDYKPzL5w4nCtobiZmSr",
  commodities: JSON.stringify([
    {
      commodity: "XTZ",
      network: "tezos",
    },
  ]),
});
```

#### 2. Display All Commodities but Provide Addresses for Some
In the example below three addresses will be pre-filled, the user can manually enter other addresses:

![3 addresses example](https://files.readme.io/e0823a5-3_addresses.gif)

```typescript
const options: Options = {
  // ... other properties
  currency: 'USD',
  commodity: 'ETH',
  network: 'ethereum',
  
  extra: {
    wallets: [
      {
        name: "ETH", // case-ignored
        network: "ethereum", // case-ignored
        address: "0x0E976df9bb3ac63F7802ca843C9d121aE2Ef22ee",
      },
      {
        name: "XTZ", // case-ignored
        network: "tezos", // case-ignored
        address: "tz1LjQKVfHCCCYm8DDYKPzL5w4nCtobiZmSr",
      },
      {
        name: "MATIC", // case-ignored
        network: "polygon", // case-ignored
        address: "0x0E976df9bb3ac63F7802ca843C9d121aE2Ef22ee",
      },
    ],
  },
};
```

#### 3. Hide Certain Commodities and Display Specific Ones with Pre-filled Addresses
The widget will load with the selected commodities and pre-filled addresses:

![Hide commodities example](https://files.readme.io/584f11c-3_Example.gif)

```javascript
const wertWidget = new WertWidget({
  // ... other properties
  commodities: JSON.stringify([
    {
      commodity: "ETH",
      network: "ethereum",
    },
    {
      commodity: "XTZ",
      network: "tezos",
    },
    {
      commodity: 'MATIC',
      network: 'polygon',
    },
  ]),
  extra: {
    wallets: [
      {
        name: "ETH", // case-ignored
        network: "ethereum", // case-ignored
        address: "0x0E976df9bb3ac63F7802ca843C9d121aE2Ef22ee",
      },
      {
        name: "XTZ", // case-ignored
        network: "tezos", // case-ignored
        address: "tz1LjQKVfHCCCYm8DDYKPzL5w4nCtobiZmSr",
      },
      {
        name: "MATIC", // case-ignored
        network: "polygon", // case-ignored
        address: "0x0E976df9bb3ac63F7802ca843C9d121aE2Ef22ee",
      },
    ],
  },
});
```

---

## Data Prefill

To simplify the purchase flow for your users, you can pass some of their details directly to Wert upon widget initialization. You are always in control of how much data you pass. You can provide ‘Know Your Customer’ information for faster user verification or just a phone number.

### Prefill Fields

| Property | Data Type | Description | Possible Values |
| --- | --- | --- | --- |
| `full_name` | string | The user’s first and last name. | Between 3 and 69 letters. `RegExp(/(\w+\s)\w+/)` |
| `date_of_birth` | string | User’s date of birth. | `DD/MM/YYYY`, `MM/DD/YYYY` (for USA) |
| `phone` | string | User’s phone number in international format (E.164 standard). The ‘+’ is optional. | `+11014321111` |
| `email` | string | User’s email address. | `test@test.com` |
| `country_of_residence` | string | User’s country of residence. | `alpha2` code of the country |
| `state_of_residence` | string | User’s state of residence (for USA). | `alpha2` code of USA state |

```javascript
const widget = new WertWidget({
  partner_id: "YOUR_PARTNER_ID",
  phone: "+494949030",
  email: "test@test.io",
  full_name: "Name Surname",
  date_of_birth: "31/07/1990",
  country_of_residence: "DE",
});
```

As a result, the user will not need to enter the data you provide manually, but they will always have the option to correct any information.

The Widget will load with pre-filled information on the following screens:
![Pre-filled screens](https://files.readme.io/e65102d-Bildschirmfoto_2023-11-30_um_14.31.11.png)

For US users, the screens will display as follows:
![US Pre-filled screens](https://files.readme.io/19f3db0-Untitled.png)

---

## Listeners Object

The listeners object helps you keep track of events in the module and respond accordingly.

### Event Reference

| Event | Expected Data | Description |
| --- | --- | --- |
| `close` | `undefined` | Triggered when the user closes a widget. |
| `error` | `{ name: String; message: String; }` | Widget error message (not payment-related), see [error codes](https://docs.wert.io/docs/error-codes). |
| `loaded` | `undefined` | Indicates the module is loaded with necessary data and ready to receive extra data if needed. May duplicate if user is redirected to bank 3D Secure page. |
| `payment-status` | `{ status: String, payment_id: String, order_id: String, tx_id: String, external_order_id: String }` | Possible statuses: `pending`, `canceled`, `failed`, `success`, `failover`. Events may not be unique per status. `tx_id` appears in `pending` status. |
| `position` | `{ step: String }` | Notifies changes in user flow position. Step values: `account`, `account-history`, `account-card`, `account-address`, `home`, `wallet`, `login`, `onboarding`, `card`, `verification`, `verification-status`, `order-review`, `order-status`, `warranty`, `error`. |
| `rate-update` | `{ ticker: String, fee_percent: String, currency_amount: String, fee_amount: String, commodity_amount: String, purchase_amount: String, miner_fee: String, currency_miner_fee: String }` | Updates when widget rate changes. Exchange rate fixed for 30 seconds. |

### Code Examples

Add the listeners object like this (key is event type, value is callback function):

```javascript
const widget = new WertWidget({
  ...options,
  listeners: {
    position: (data) => console.log("step:", data.step),
  },
});
```

To subscribe to payment status data:

```javascript
const widget = new WertWidget({
  ...options,
  listeners: {
    'payment-status': data => console.log('Payment status:', data)
  },
});
```
*Note: Payment status listener will only be triggered when simulating the purchase, not in intermediary steps.*

---

## Widget Display Methods

After creating and configuring the widget, you can use methods to control the widget's display.  
*Please ensure you use the latest SDK version (7.x.x).*

| Method | Description |
| --- | --- |
| `open` | Mount the widget in the DOM and make it visible (initializes widget as an iFrame). |
| `close` | Close the widget modal. |
| `updateTheme` | Switch the widget's theme without reloading it. |
| `addEventListeners` | Add event listeners. See [listeners object](https://docs.wert.io/docs/listerners-object). |
| `removeEventListeners` | Remove event listeners. |

### Method Usage Examples

```javascript
// Open widget
wertWidget.open();

// Switch theme without reloading (call after widget is fully loaded)
wertWidget.updateTheme({
  theme: 'dark', // Use 'undefined' for default light theme
  brand_color: 'red' // String, HEX, RGB, etc.
});

// Add event listeners
wertWidget.addEventListeners({
  position: data => console.log('step:', data.step),
});

// Remove event listeners
wertWidget.removeEventListeners('rate-update');
wertWidget.removeEventListeners([ 'rate-update', 'payment-status' ]);
wertWidget.removeEventListeners();
```

---

## Converter API Reference

The converter endpoint allows you to receive information on a transaction without going through the execution flow. You can use the response to display the exact amount before opening the widget or pass the amount directly into the widget.

### Endpoints

| Environment | URL | Method |
| --- | --- | --- |
| `Sandbox` | `https://sandbox.wert.io/api/v3/partners/convert` | `POST` |
| `Production` | `https://widget.wert.io/api/v3/partners/convert` | `POST` |

**Headers:**
```
X-Partner-ID: YOUR_PARTNER_ID
Content-Type: application/json
```

### Rate Limit

To ensure API stability and fair usage, a rate limit is implemented on all conversion requests. Exceeding limits returns a `429 Too Many Requests` error.

* **Threshold:** 1 request per 250 ms per IP address.
* **Throughput:** Approximately 4 requests per second.
* **Lockout Period:** Any request sent within 250 ms of the previous request from the same IP returns `429 - Too Many Requests`.

> **Recommendation:** Implement conversion logic or a request throttler directly in your frontend to prevent hitting these limits.

### Parameters

> **Note:** Only `USD` is available in sandbox.

| Property | Required | Type | Description |
| --- | --- | --- | --- |
| `from` | Yes | string | Base asset (Fiat or Crypto). Refer to [Supported coins and blockchains](https://docs.wert.io/docs/supported-coins-and-blockchains). |
| `network` | Yes | string | Base asset network. Refer to [Supported coins and blockchains](https://docs.wert.io/docs/supported-coins-and-blockchains). |
| `to` | Yes | string | Quote asset (Fiat or Crypto). Refer to [Supported coins and blockchains](https://docs.wert.io/docs/supported-coins-and-blockchains). |
| `amount` | Yes | numerical | Base asset amount. |
| `partner_data` | For smart contract | object | Partner data object. |
| `sc_address` | For smart contract | string | Address of your smart contract. |
| `sc_input_data` | For smart contract | string | Hex format input data for smart contract execution. |
| `signature` | For smart contract | string | Digital signature used to encrypt and authenticate the request. |

### Request Examples

#### Crypto Transaction
```bash
curl -X POST --url 'https://sandbox.wert.io/api/v3/partners/convert' -H 'Content-Type: application/json' -H 'X-Partner-ID: your-partner-id' -d '{
    "from": "ETH",
    "network": "sepolia",
    "to": "USD",
    "amount": 0.05
}'
```

#### Smart Contract Transaction
```bash
curl -X POST --url 'https://sandbox.wert.io/api/v3/partners/convert' -H 'Content-Type: application/json' -H 'X-Partner-ID: your-partner-id' -d '{
    "from": "ETH",
    "network": "sepolia",
    "to": "USD",
    "amount": 0.05,
    "partner_data": {
      "sc_address": "0xC545CEae428785a5AE77bfF262600deC7F7d76d2",
      "sc_input_data": "0x9dae76ea000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000",
      "signature": "d035046e8eda9b2c9c4413bfd31ed42b7df056108c83110aa8ae70f9ca167e1a2047d1b906afa66a770939dd074d1eff27b029ec2c27b39dc30a076e31221209"
    }
}'
```

### Response Parameters

| Parameter | Description |
| --- | --- |
| `ticker` | The rate at which cryptocurrency is being sold. |
| `fee_percent` | % fee taken by the service. |
| `currency_amount` | Final amount in fiat that the user will pay. |
| `fee_amount` | Amount paid in fiat to cover the service fee. |
| `commodity_amount` | Amount of cryptocurrency that the user will receive. |
| `purchase_amount` | Fiat amount used to buy crypto (`purchase_amount` = `currency_amount` - `fee_amount` - `currency_miner_fee`). |
| `miner_fee` | Amount of crypto used to cover blockchain network fees. |
| `currency_miner_fee` | Price of miner fee in fiat (`currency_miner_fee` = `miner_fee` * `ticker`). |

### Sample Responses

#### 200 (OK)
```json
{
  "status": "ok",
  "body": {
    "ticker": 2672.540034535,
    "fee_percent": 0.05,
    "currency_amount": 144.3,
    "fee_amount": 6.87,
    "commodity_amount": 0.05,
    "purchase_amount": 137.43,
    "miner_fee": 0.00142144,
    "currency_miner_fee": 3.8
  }
}
```

#### 400 (Bad Request Options)
```json
{
  "status": "error",
  "error_description": "amount: must be no less than 0.",
  "request_id": "string"
}
```
```json
{
  "status": "error",
  "error_description": "amount is too low",
  "request_id": "string"
}
```
```json
{
  "status": "error",
  "error_description": "from: cannot be blank; to: cannot be blank.",
  "request_id": "string"
}
```
```json
{
  "code": 1302,
  "status": "error",
  "error_description": "unknown commodity",
  "request_id": "424f8c727a9b2664f2de61c16b5cf169"
}
```
```json
{
  "code": 1301,
  "status": "error",
  "error_description": "commodity is disabled",
  "request_id": "83c4bbaa60198284846fd77e0bb72293"
}
```
```json
{
  "code": 1013,
  "status": "error",
  "error_description": "unknown currency",
  "request_id": "701f7153101206e1e2ef871aa539f40b"
}
```
```json
{
  "code": 9001,
  "status": "error",
  "error_description": "the partner doesn't exist",
  "request_id": "76fec9b0ba9fda16c68a4ca2d038186d"
}
```

---

## Error Codes Reference

### Locating Error Responses

To locate error responses using Developer Tools:
1. Go to the page with the error.
2. Right-click and select `Inspect`.
3. Go to the `Network` tab.
4. Perform the action that triggers the error or refresh the page.
5. Look for the red-highlighted request (the error endpoint).
6. Click the request to view details, inspecting `Preview` and `Response`.
7. Identify the error code and refer to the troubleshooting steps below.

When contacting Partner Support, please provide:
* Request ID
* Payload
* Request URL

![Inspecting network tab](https://files.readme.io/3a59d72-0216-ezgif.com-video-to-gif-converter.gif)

---

### Error Codes Catalogue

#### Error Code 8001: Blockchain Execution Reverted
* **Endpoint:** `/convert`
* **Cause:** Issue in contract/input data, or item has already been purchased. Text after `"execution reverted"` is the response from your smart contract. If no response is present, the contract may not be verified or error responses are not set up.
* **Troubleshooting Steps:**
  1. [Verify your smart contract](https://docs.wert.io/docs/verifying-your-smart-contract). If using a proxy contract, save the proxy address against the ABI of the implementation contract.
  2. Check if input data matches the ABI of the contract (use an EVM ABI decoder).
  3. If your smart contract requires whitelisting, ensure both Wert Hot Wallet and Estimation addresses are whitelisted. Contact support for current wallet addresses.
  4. Ensure amount precision does not exceed allowed decimal places (see Decimal Precision table).
  5. Check contract restrictions/limitations that would block executing input data.
  6. Share a successful transaction hash executing the same input data if issue persists.

#### Error Code 8002: Blockchain Invalid Input Data
* **Endpoint:** `/convert`
* **Cause:** Input data was incorrect before being sent to the node (variables/method name do not match).
* **Troubleshooting Steps:** Check input data variables and methods for errors.

#### Error Code 8003: Blockchain Transaction Injection Error
* **Endpoint:** `/convert`
* **Cause:** Node error (e.g., `invalid method name`).
* **Troubleshooting Steps:** Inspect node response in description. Verify Wert wallet balance.

#### Error Code 9001: Partner Does Not Exist
* **Endpoint:** `./partners/{partner_id}`
* **Cause:** Partner ID not found in Wert database.
* **Troubleshooting Steps:** Verify environment credentials. Ensure `partner_id` corresponds to the active environment (Sandbox vs Production).

#### Error Code 9004: Partner Data Not Verified By Signature
* **Endpoint:** `./validate-smart-contract`
* **Cause:** Signature does not correspond to input data (wrong data signed).
* **Troubleshooting Steps:**
  1. Verify all required parameters are signed in correct order (see [signed data guide](https://docs.wert.io/docs/generate-signed-data)).
  2. Ensure `commodity_amount` in signed data has no more than 8 decimal places (round up if needed).
  3. Verify private and public keys.

#### Error Code 9005: Partner Unverified Contract
* **Endpoint:** `./validate-smart-contract`
* **Cause:** Smart contract unverified on Etherscan/Polygonscan or Wert database.
* **Troubleshooting Steps:** Verify contract on Etherscan/Polygonscan or follow the [verification guide](https://docs.wert.io/docs/verifying-your-smart-contract).

#### Error Code 9006: Partner Disabled SC
* **Endpoint:** `./validate-smart-contract`
* **Cause:** Smart Contracts disabled for this partner ID.
* **Troubleshooting Steps:** Verify environment (production vs sandbox). Contact Wert support with Partner ID if environment is correct.

#### Error Codes 1301 & 1302: Commodity Unknown / Commodity Disabled
* **Endpoints:** `/assets`, `/convert`, `/partner/convert`
* **Cause:** Commodity does not exist or is disabled.
* **Troubleshooting Steps:** Verify `commodity`, `network`, and `origin` match the active environment (production or sandbox). See [Supported coins and blockchains](https://docs.wert.io/docs/supported-coins-and-blockchains).

#### Error Code 1304: Parent Commodity Disabled
* **Endpoint:** `/assets`
* **Cause:** Parent commodity is disabled.
* **Troubleshooting Steps:** Contact support to enable parent commodity or get guidance.

#### Error Code 1305: Commodity Has No Available Pairs
* **Endpoint:** `/assets`
* **Cause:** Commodity enabled but lacks active trading pairs for the partner.
* **Troubleshooting Steps:** Select a different commodity with active trading pairs.

#### Error Code 1400: Contract Not Payable
* **Endpoint:** `./validate-smart-contract`
* **Cause:** Issue verifying smart contract payability.
* **Troubleshooting Steps:**
  1. Verify `sc_address` and `address` contain valid data.
  2. [Verify your smart contract](https://docs.wert.io/docs/verifying-your-smart-contract).

#### Error Code 1013: Invalid Field
* **Endpoint:** `./validate-smart-contract`
* **Cause:** Invalid request data or below minimum transaction threshold.
* **Troubleshooting Steps:**
  1. Minimum order amount is ~$1.50 in sandbox and ~$5.00 in production. Update `commodity_amount` to meet the minimum.
  2. Ensure `address` and `sc_address` contain valid data.

#### SDK General Errors
* **Examples:** Full-screen issues, redirect problems, transparent OTP screen.
* **Troubleshooting Steps:** Upgrade to the latest version of the [@wert-io/widget-initializer SDK](https://www.npmjs.com/package/@wert-io/widget-initializer).

#### Sandbox FKYC Issues
* **Examples:** Stuck on verification complete screen.
* **Troubleshooting Steps:** Create a new sandbox account using a random phone number (sandbox OTP is always `0000`).

#### OTP Not Received
* **Cause:** Delayed or blocked SMS OTP.
* **Troubleshooting Steps:**
  * Note: Sandbox OTP is always `0000`.
  * For production:
    1. Check phone signal strength.
    2. Confirm mobile carrier is not experiencing outages.
    3. Ensure phone settings permit international SMS (some carriers block foreign senders by default).
    4. Follow detailed [OTP troubleshooting guide](https://docs.wert.io/docs/going-live#%EF%B8%8F-otp--sms-troubleshooting).
    5. Contact support if issue persists.

---

## Supported Coins and Blockchains

### Production

| Cryptocurrency | Available Networks | `commodity` Option | `network` Option | Smart Contract Support | Decimal Precision |
| --- | --- | --- | --- | --- | --- |
| Aavegotchi | Polygon | `'GHST'` | `'polygon'` | Yes | 18 |
| Arbitrum | Arbitrum | `'ARB'` | `'arbitrum'` | Yes | 18 |
| AVAX | Avalanche | `'AVAX'` | `'avalanche'` | Yes | 18 |
| Binance Coin | Binance | `'BNB'` | `'bsc'` | Yes | 18 |
| Bitcoin | Bitcoin | `'BTC'` | `'bitcoin'` | No | 8 |
| Bone ShibaSwap | Shibarium | `'BONE'` | `'shibarium'` | Yes | 18 |
| Concordium | Concordium | `'CCD'` | `'concordium'` | Yes | 5 |
| cUSDT | Ethereum | `'CUSDT'` | `'mainnet'` | No | 6 |
| Ethereum | Ethereum, Arbitrum, Base, Hemi | `'ETH'` | `'ethereum'`, `'arbitrum'`, `'base'`, `'hemi'` | Yes | 18 |
| EUROe | Concordium | `'EUROE'` | `'mainnet'` | No | 6 |
| GPRO | Polygon | `'GPRO'` | `'polygon'` | Yes | 18 |
| Hemi | Hemi | `'HEMI'` | `'hemi'` | Yes | 18 |
| LayerAI | Ethereum, Binance | `'LAI'` | `'ethereum'`, `'bsc'` | No | 18 |
| LimeWire | Ethereum | `'LMWR'` | `'ethereum'` | Yes | 18 |
| MANA | Polygon, Ethereum | `'MANA'` | `'polygon'`, `'ethereum'` | Yes | 18 |
| NEAR | Near | `'NEAR'` | `'near'` | Yes | 8 |
| opBNB | opBNB | `'OPBNB'` | `'opbnb'` | Yes | 18 |
| POL | Polygon | `'POL'` | `'polygon'` | Yes | 18 |
| Rootstock BTC | Rootstock | `'RBTC'` | `'rootstock'` | Yes | 18 |
| Stacks | Stacks | `'STX'` | `'stacks'` | No | 6 |
| Solana | Solana | `'SOL'` | `'solana'` | Yes | 9 |
| Tezos | Tezos | `'XTZ'` | `'tezos'` | Yes | 6 |
| Tezos | Etherlink | `'XTZ'` | `'etherlink'` | Yes | 18 |
| TFUEL | Theta | `'TFUEL'` | `'theta'` | Yes | 18 |
| TON | The Open Network | `'TON'` | `'ton'` | Yes | 8 |
| USDC | Arbitrum, Base, Ethereum, Avalanche, Shibarium, Solana, Polygon, Hemi, Etherlink | `'USDC'` | `'arbitrum'`, `'base'`, `'ethereum'`, `'avalanche'`, `'shibarium'`, `'solana'`, `'polygon'`, `'hemi'`, `'etherlink'` | Yes | 6 |
| USDSM | Etherlink | `'USDSM'` | `'etherlink'` | Yes | 18 |
| USDT | Polygon, Ethereum, Binance, TON, Hemi | `'USDT'` | `'polygon'`, `'ethereum'`, `'bsc'`, `'ton'`, `'hemi'` | Yes | Polygon: 6, Ethereum: 6, BSC: 18, TON: 6, Hemi: 6 |
| Vyvo | Vyvo | `'VSC'` | `'vyvo'` | Yes | 5 |
| Wrapped Ether | Polygon | `'WETH'` | `'polygon'` | Yes | 18 |
| XCAD | opBNB, Binance | `'XCAD'` | `'opbnb'`, `'bsc'` | Yes | 18 |

---

### Sandbox

| Cryptocurrency | Available Networks | `commodity` Option | `network` Option | Decimal Precision |
| --- | --- | --- | --- | --- |
| Binance | BSC | `'BNB'` | `'bsc'` | 18 |
| BONE | Puppynet | `'BONE'` | `'puppynet'` | 18 |
| Concordium | Concordium | `'CCD'` | `'concordium'` | 18 |
| cUSDC | Sepolia | `'cUSDC'` | `'sepolia'` | 6 |
| Ethereum | Sepolia, Base, Arbitrum | `'ETH'` | `'sepolia'`, `'base_sepolia'`, `'arbitrum_sepolia'` | 18 |
| EUROe | Concordium | `'EUROe'` | `'concordium'` | 18 |
| Hemi | Hemi | `'HEMI'` | `'hemi'` | 18 |
| POL | Amoy | `'POL'` | `'amoy'` | 18 |
| Solana | Solana | `'SOL'` | `'solana'` | 9 |
| Test Token | Amoy, BSC, KuCoin, Base, Arbitrum Sepolia, Sepolia, opBNB, Puppynet, Hemi, Etherlink | `'TT'` | `'amoy'`, `'bsc'`, `'kucoin'`, `'base_sepolia'`, `'arbitrum_sepolia'`, `'sepolia'`, `'opbnb'`, `'puppynet'`, `'hemi'`, `'etherlink'` | 18 |
| Test Token | Solana | `'TT'` | `'solana'` | 9 |
| Tezos | Ghostnet, Etherlink | `'XTZ'` | `'ghostnet'`, `'etherlink'` | 6 |
| opBNB | opBNB | `'opBNB'` | `'opbnb'` | 18 |
| USDSM | Etherlink | `'usdsm'` | `'etherlink'` | 18 |

#### Sandbox Test Token Contracts

Test Token (`TT`) is the only ERC-20 token available in sandbox. It is a standard ERC-20 token used to test smart contract interactions.

To acquire Test Tokens for testing, simulate a purchase in sandbox to transfer tokens to your wallet address. You will not be charged; please return tokens after testing.

Deployed Contract Addresses:
* **Arbitrum Sepolia:** `0x103EF343661335B85BE98EfEfF7f726Be7CeeeDE`
* **Ethereum Sepolia:** `0x42D8BCf255125BB186459AF66bB74EEF8b8cC391`
* **Polygon Amoy:** `0x834bBE71a0a5C91A4Aff10Df400A963D95AD4775`
* **Binance Smart Chain (BSC):** `0x4C07B79C3D8954A51Efc342EdA5D08f8b1f9ceC4`
* **Base Sepolia:** `0x3bE123Ff0ec7c0717D6C05C8957EA7880e2FfDcb`
* **Puppynet:** `0x4C07B79C3D8954A51Efc342EdA5D08f8b1f9ceC4`
* **Solana:** `Hza3mZYRv7ZZw2xo1kvWvD4YXLnhA47JtTZBhgr8LTU7`
* **Hemi:** `0x33e8Bf90e1aafcE42490e05880810f6d09699e02`

## Frontend Integration Code Examples

### Widget Initialization Example

```typescript
import WertWidget from '@wert-io/widget-initializer';
import type { Options } from '@wert-io/widget-initializer/types';
import { v4 as uuidv4 } from 'uuid';

const options: Options = {
  partner_id: '01GCRJZ1P7GP32304PZCS6RSPD',
  click_id: uuidv4(), // unique id of purchase in your system
  origin: 'https://sandbox.wert.io', // needed only in sandbox
  commodity: 'ETH',
  network: 'sepolia',
  commodities: JSON.stringify([
    {
      commodity: 'POL',
      network: 'amoy',
    },
    {
      commodity: 'ETH',
      network: 'sepolia',
    },
  ]),
  listeners: {
    loaded: () => console.log('loaded'),
  },
};

const wertWidget = new WertWidget(options);
wertWidget.open();
```

### TypeScript Definition Types

```typescript
// Main options types
export type Options = {
  partner_id: string;
  click_id?: string;
  origin?: string;
  lang?: string;
  address?: string;
  theme?: ThemeType;
  brand_color?: string;
  currency_amount?: number;
  country_of_residence?: string;
  state_of_residence?: string;
  date_of_birth?: string;
  full_name?: string;
  commodity?: string;
  commodity_amount?: number;
  network?: string;
  commodities?: string;
  currencies?: string;
  phone?: string;
  user_id?: string;
  email?: string;
  redirect_url?: string;
  support_url?: string;
  extra?: ExtraOptions;
  listeners?: EventListeners<WidgetEvents>;
  skip_init_navigation?: boolean;
  is_crypto_hidden?: boolean;
  session_id?: string;
  terms_on_payment?: boolean;
  payment_method?: string;
  payment_method_restriction?: boolean;
  display_currency?: string;
  hide_fee_breakdown?: boolean;
  is_auto_logout_on_order_complete_enabled?: boolean;
  is_session_expire_on_email_mismatch?: boolean;
} & CardBillingAddressOptions & SCOptions;

type CardBillingAddressOptions = {
  card_country_code?: string;
  card_city?: string;
  card_state_code?: string;
  card_post_code?: string;
  card_street?: string;
}
type SCOptions = {
  sc_address?: string;
  sc_input_data?: string;
  signature?: string;
};

export interface ExtraOptions {
  item_info?: ItemInfo;
  wallets?: Wallet[];
}

interface ItemInfo {
  author_image_url?: string;
  author?: string;
  image_url?: string;
  name?: string;
  category?: string;
  seller?: string;
  header?: string;
}
interface Wallet {
  name: string;
  network: string;
  address: string;
}

type ThemeType = 'dark' | undefined;

export type SetThemeParameters = {
  theme?: ThemeType;
  brand_color?: string;
};

// Event Types
export type EventTypes =
  | 'close'
  | 'error'
  | 'loaded'
  | 'payment-status'
  | 'position'
  | 'rate-update';

export type InternalEventTypes = '3ds-start' | '3ds-end';

interface WidgetEvent<EventType extends EventTypes | InternalEventTypes> {
  type: EventType;
}

type CloseEvent = WidgetEvent<"close">

type LoadedEvent = WidgetEvent<"loaded">

interface ErrorEvent extends WidgetEvent<"error"> {
  data: { name: string; message: string };
}

interface PaymentStatusEvent extends WidgetEvent<"payment-status"> {
  data: {
    status: string;
    payment_id: string;
    order_id: string;
    tx_id?: string;
    external_order_id: string;
  };
}

interface PositionEvent extends WidgetEvent<"position"> {
  data: { step: string };
}

interface RateUpdateEvent extends WidgetEvent<"rate-update"> {
  data: {
    ticker: string;
    fee_percent: string;
    currency_amount: string;
    fee_amount: string;
    commodity_amount: string;
    purchase_amount: string;
    miner_fee: string;
    currency_miner_fee: string;
  };
}

type Start3dsEvent = WidgetEvent<"3ds-start">
type End3dsEvent = WidgetEvent<"3ds-end">

export type WidgetEvents =
  | CloseEvent
  | ErrorEvent
  | LoadedEvent
  | PaymentStatusEvent
  | PositionEvent
  | RateUpdateEvent;

export type InternalWidgetEvents = Start3dsEvent | End3dsEvent;

type EventListeners<Events extends { type: string; data?: Record<string, unknown> }> = {
  [E in Events as E["type"]]?: E extends { data: Record<string, unknown> } ? (event: E["data"]) => any : () => any;
}
```
````

<br />