# Direct Topup Webhook

### Overview <a href="#overview" id="overview"></a>

**Direct topup webhook (order notification) is now available for topup products, enabling sellers to accept more orders than their current inventory (declared stock) by integrating with external topup providers.**

The "Direct Topup Webhook" feature allows you as a seller to automate top-up transactions for gaming products without manually managing individual transactions. The Direct-topup Webhook feature enables real-time top-up processing for gaming products, allowing you to provide instant top-up services through automated API integration .<br>

### **Enabling "Direct Topup Webhook" Feature**

You can enable the direct topup webhook feature directly from your Driffle dashboard. Follow the steps below to enable direct topups for your products:

1. **Login to your `seller dashboard`.**
2. Navigate to `Store Settings` **> `Direct Top-up Webhook`.**                                                        &#x20;

**Step 1: Connect Webhook**

To begin, you must connect and verify your system's endpoints with Driffle.

* **Dummy Product Offer:** We have created a dummy offer for product ID: 888888. This product will not be visible to users. This is for you to test that the endpoints are configured with the correct responses on production.
* **Authorization:** Provide your API key in the `Bearer` token field for authenticating requests between Driffle and your system.
* **Recharge details:** Enter a test `User ID` and `Server ID` that your system can use to process the dummy top-up request. These are test payload, actual payload will be different for each topup product.
* **Validation Webhook:** Enter the URL of your endpoint that will handle top-up validatin.Driffle will send a request to this endpoint to validate the `User ID` and `Server ID` before processing the top-up. This helps prevent incorrect top-ups and avoids unnecessary refunds when user details are invalid.
* &#x20;**Direct topup webhook:** Enter the URL of your endpoint that will handle the top-up provisioning. Driffle will send a request to this endpoint to credit the user's account. Once entered, click "Verify" to ensure your endpoint is reachable and responds correctly. A "Verified" status will appear upon successful connection. \
  For detailed request and response formats, refer to the [#topup-order-flow](#topup-order-flow "mention")

After filling in all the required fields and verifying the endpoint, click **Save**.<br>

<figure><img src="/files/AEbhjCLyHwmk1rpZflIU" alt=""><figcaption></figcaption></figure>

**Step 2: Enable Feature**

Once your endpoints are successfully connected and verified, you can enable the direct topup feature.

* Read the terms and conditions for selling with the linked API.
* Check the box for "I agree to the terms and conditions."
* Click **Enable** to finalize the setup.<br>

  <figure><img src="/files/BWZsdVLUOCPex3IM8C9y" alt=""><figcaption></figcaption></figure>

### API Reference: Accessing Form Fields Schema

For developers integrating with our system, the form\_fields object has been added to the response payloads of the [Product](/driffle-seller-api-legacy/reference/api-reference/products/get-products-list.md) and [Offers APIs](/driffle-seller-api-legacy/reference/api-reference/offers-auction/offers-list.md). This object defines the structure of account information required for topup.

#### A. Product List & Single Product Details API

When fetching the product list or details for a specific Item ID, the response now includes the form\_fields parameter. This describes the schema (data types, labels, and validation rules) required for the product.

**Endpoint Reference:**

{% content-ref url="/pages/ZDNpLGxVgMYHDvLRa4Ux" %}
[Products](/driffle-seller-api-legacy/reference/api-reference/products.md)
{% endcontent-ref %}

**New Response Parameter:**

* **formFields**: Contains the JSON schema for dynamic inputs. This object defines the structure of account information required for topup.
* Each field object contains:
  * **name** – field identifier
  * **type** – `string` , `number`or `enum`
  * **value** – allowed options when type is enum (e.g., `"android | ios"`).

<pre class="language-json"><code class="lang-json"><strong>"formFields": [
</strong>    {
        "name": "userid",
        "type": "string"
    },
    {
        "name": "device",
        "type": "enum",
        "value": "android | ios"
    }
]
</code></pre>

When placing an order for a top-up product, the values from **formFields** must be sent as:

```json
"formFields": {
    "userid": "12345678",
    "device": "android"
}
```

**Notes**

* Keys inside `formFields` of the order request must exactly match the `name` values provided in the `formFields` array from the product response.
* For `enum` fields, only one of the allowed values should be sent.

#### B. Offers API

The Offers API has also been updated. When creating or retrieving offers, the form\_fields data ensures that your system knows exactly what information must be collected or validated during the transaction.

**Endpoint Reference:**

{% content-ref url="/pages/VAcTABjhpSiucfs7BpLf" %}
[Offers (Auction)](/driffle-seller-api-legacy/reference/api-reference/offers-auction.md)
{% endcontent-ref %}

## **Topup Order Flow**

There are **two main webhook stages**:

1. Validation Webhook
2. Topup Webhook

<figure><img src="/files/WrZABuZt5G3SYW0nPg5z" alt=""><figcaption></figcaption></figure>

### Validation-Webhook ( formerly reservation endpoint ) <a href="#provision-endpoint" id="provision-endpoint"></a>

**Note:** Do not perform any topup during validation.

**Request Body**

```
{
  offers: {
    offerId: number;
    formFields: { [key: string]: string | number };
  }[];
```

```json
{
  "offers": [
    {
      "offerId": 10542,
      "formFields": {
         "userid": "12345678",
         "device": "android"
      }
    }
  ]
}
```

#### Response <a href="#response.1" id="response.1"></a>

By successfully responding (HTTP status 200) to the reservation request with the payload structure below, you indicate status of user details.

```json
{
  "message": "Validation successful",
  "data": {
    "offers": [
      {
        "offerId": 12123875,
        "formFields": {
          "userid": "12345678",
          "device": "android"
        },
        "validationstatus": false,
        "validationmessage": "Validation failed due region not supported"
      }
    ]
  }
}
```

### Topup-Webhook ( formerly provision endpoint ) <a href="#provision-endpoint" id="provision-endpoint"></a>

#### Request Body <a href="#request-body.1" id="request-body.1"></a>

**Note:**  `offers` array  contain **one item only**, and `quantity` will  be **1**.

```json
{
orderId: string;
  offers: {
    offerId: number;
    quantity: number;
    price: {
      yourPrice: number;
      sellingPrice: number;
      currency: string;
    };
    formFields: { [key: string]: string | number };
  }[];
  }
```

```json
{
  "orderId": "aArg23fvas",
  "offers": [
    {
      "offerId": 10542,
      "quantity": 1,
      "price": {
        "yourPrice": 9.50,
        "sellingPrice": 10.00,
        "currency": "EUR"
      },
      "formFields": {
         "userid": "12345678",
         "device": "android"
      }
    }
  ]
}
```

#### Response <a href="#response.1" id="response.1"></a>

By successfully responding (HTTP status 200) to the Provision request with the payload structure below, you indicate that you can fully fulfill the topup provision.

```json
{
  "message": "",
  "data": {
    "orderId": "aArg23fvas",
    "transactionId": "dsdssdfdsfsewrwwfss",
    "offers": [
      {
        "offerId": 10542,
        "topupDetails": {
          "amount": 10,
          "currency": "EUR",
          "status": "completed"
        }
      }
    ]
  }
}
```

#### Response Data Fields <a href="#response-data-fields" id="response-data-fields"></a>

| Field         | Type             | Description                          |
| ------------- | ---------------- | ------------------------------------ |
| orderId       | string           | Provision Order Id for topup purchas |
| transactionId | string           | Your internal transaction ID         |
| offers        | \[webhookOffers] | Array of offers                      |

#### webhookOffers Fields <a href="#topupdetails-fields" id="topupdetails-fields"></a>

| Field        | Type   | Description                       |
| ------------ | ------ | --------------------------------- |
| offerId      | string | drifflr offerId                   |
| topupDetails | object | Details about the completed topup |

#### TopupDetails Fields <a href="#topupdetails-fields" id="topupdetails-fields"></a>

| Field    | Type   | Description                                                             |
| -------- | ------ | ----------------------------------------------------------------------- |
| amount   | number | The topup amount                                                        |
| currency | string | Currency code ( `USD` , `EUR` , etc.)                                   |
| status   | string | Status of the top-up ( `completed` , `accepted`, `failed` , `pending` ) |

#### API Response Status Guide

When our system sends a web hook for topup product to your API with **60s** timeout, we expect a JSON response containing an order\_status field. This status determines how we handle the order lifecycle (whether we mark it complete, fail it, or wait for processing).

The topup provision system recognizes three primary status categories. When our system sends a Provision (Top-up) request to your API, we expect a JSON response containing an `order_status` field. This status determines how we handle the order lifecycle (whether we mark it complete, fail it, or wait for processing).

#### 1. `completed` Status (Immediate Fulfillment)

The top-up has been successfully delivered to the user's account immediately upon request

* The order is fully processed and no further action is needed
* The customer has received their recharge

Return this status when the top-up has been successfully delivered to the user's account immediately upon request

* Use `completed` when the topup has been immediately processed by the seller and the customer has received the recharge
* Use `accepted` when you have confirmed the order and will fulfill it immediately (**within 30 min**), or when your system guarantees fulfillment. Use this when you want to do the topup manually&#x20;
* The order is marked as Delivered when either of `accepted` or `completed`  is sent in `order_status` field.
* The customer is notified that their top-up is done.
* No further API calls will be made for this specific order.
* No retry job is scheduled
* The order is considered final and complete
* Our system will NOT call your API again for this specific order.
* Do not return success status if the order is still processing - use `pending` instead.

#### 2. `pending`  Status

Return `pending` status if you have received the request, but the top-up is still processing (e.g., waiting on an upstream provider or a slow network).

* You have received the request, but the top-up is still processing
  * The order is waiting on an upstream provider or a slow network
  * The final outcome is not yet determined
* The order is marked as Processing in our system.
* Return `pending` status if you have received the request, but the top-up is still processing

  * Use when your provider requires time to process the recharge
  * Use when you need to verify the recharge with a third-party provider
  * Use when the order is queued in your system but not yet executed
  * The order is NOT marked as complete or failed at this stage

  #### How it works:

  1. **Initial Response Handling:**

     * When your API returns a pending status (`pending`), our system marks the order as `pending`
     * The order is NOT marked as complete or failed at this stage

     &#x20;     &#x20;

  2. &#x20;**Automatic Retry Process:**

     * **Initial Retry:** After 5 seconds, our system re-calls your web hook endpoint  with the same payload
     * **Subsequent Retries:** Up to 3 additional retries with 10-minutes delays between each
     * **Total Coverage:** \~30 minutes (5s initial + 10m + 10m + 10m)
     * **Total API Calls:** 4 calls (initial + 3 retries)

  3. Each retry re-calls your web hook endpoint with the same `orderId` and payload

     * If your API returns `completed` or `accepted` → Order is marked as `REDEEMED` and retries stop
     * If your API returns `failed` → Order is marked as `DEFECTIVE`, refund is triggered, and retries stop
     * If still `pending` after all retries → Order is marked as `failed` and refund is triggered

  4. **Idempotency Requirement (CRITICAL):**
     * web hook endpoint **MUST be idempotent**
     * When we call your API with the same `orderId` multiple times, you should return the **current status** of that order
     * Do NOT create duplicate orders or recharge the customer multiple times.
     * If the order completes during the retry period, return a success status on the next retry
     * If processing takes longer than 50 seconds, the order will be marked as failed after all retries

#### 3. `failed` Status

Return a `failed` status if the top-up cannot be processed (e.g., invalid Player ID, out of stock, or technical error).

* The order is marked as Failed.
* The transaction is reversed/refunded on our side.
* No further actions are taken.
* The top-up cannot be processed
  * The order was rejected or could not be fulfilled

| Your API Status         | Our System Interpretation | Action Taken                             |
| ----------------------- | ------------------------- | ---------------------------------------- |
| `completed`/ `accepted` | Order Complete            | Transaction finalized.                   |
| `pending`               | Order In-Progress         | We start retrying your webhook endpoint. |
| `failed`                | Order Failed              | Transaction cancelled/refunded.          |

Status matching is case-sensitive

* Ensure your API returns status values that match your configured mappings
* Unknown statuses (not in any mapping) are treated as failures after retries are exhausted

> Important: We never "retry" a provision request that you have already accepted (i.e., we won't accidentally purchase the item twice). If you say "Pending," we only ask "Is it done?" via the Status API.

## Topup order status (notify Driffle)

This page goes with: [Direct Topup Webhook](https://docs.driffle.com/driffle-seller-api-legacy/reference/direct-topup-webhook).

After you process a direct top-up order, call the URL below to tell Driffle whether it **completed** or **failed**. This is different from the validation and provision webhooks in the guide above — those are URLs **we** call on **your** servers. This one is a URL **you** call on **ours**.

#### When to use it

Send a result when you know the final outcome for an order: either the top-up succeeded (**completed**) or it could not be delivered (**failed**). Use the same **order id** string Driffle sent you in the provision (top-up) webhook request body.

**Good to know**

* A normal success response means we accepted your notification; it does not replace any other checks on your side.
* You must authenticate with the **Topup API key** from your seller dashboard (same key you use for Direct Top-up / Topup API setup).

#### URL and method

|            |                                                                             |
| ---------- | --------------------------------------------------------------------------- |
| **URL**    | `https://services.driffle.com/api/seller/legacy/webhook/topup/order-status` |
| **Method** | `POST`                                                                      |
| **Body**   | JSON (see below)                                                            |

If you use another Driffle environment (staging, etc.), keep the same pattern as your other **Seller Legacy** API calls: same host and `/api/seller/legacy` prefix, then `/webhook/topup/order-status`.

#### Authentication

Add this header:

```http
Authorization: Bearer <YOUR_TOPUP_API_KEY>
```

Use the Topup API key from **Seller dashboard → Store settings → Direct Top-up** (or wherever you manage your Topup API key). The key must be active and verified.

* Wrong or missing key → **401** and `status: 0` in the JSON body.

#### Request body (JSON)

| Field     | Type   | Required | Description                                                                              |
| --------- | ------ | -------- | ---------------------------------------------------------------------------------------- |
| `orderId` | string | Yes      | The Driffle order id for this top-up (same as in the provision webhook).                 |
| `status`  | string | Yes      | `completed` if the top-up succeeded, `failed` if it could not be completed.              |
| `message` | string | Yes      | Short text for both cases: e.g. success note for `completed`, clear reason for `failed`. |

**Example — success**

```json
{
    "orderId": "aArg23fvas",
    "status": "completed",
    "message": "Top-up credited successfully"
}
```

**Example — failure**

```json
{
    "orderId": "aArg23fvas",
    "status": "failed",
    "message": "Upstream provider rejected the player ID"
}
```

**Notes**

* Which **store** the order belongs to is inferred from your API key — do not rely on extra fields for that.
* Only the fields above are required; any other JSON fields may be ignored.

#### When we accept or reject the call

We return **400** if something is wrong with the request or the order, for example:

* The `orderId` does not match a top-up order for your store.
* There is more than one top-up line on the same order — we use the first one in a consistent order.
* The order is not in a state that allows this notification.
* The order is too old (more than **30 minutes** since it was created).

The JSON body of the error usually includes a **message** explaining what went wrong.

#### Responses

Every JSON response includes **`orderId`** (string) when your request body contained an `orderId`, so you can match the reply to the order you sent.

| Field     | Type   | Description                                                                             |
| --------- | ------ | --------------------------------------------------------------------------------------- |
| `status`  | number | `1` = accepted, `0` = error.                                                            |
| `message` | string | Short outcome or error text.                                                            |
| `orderId` | string | Echo of the `orderId` from your request (omitted only if the request had no `orderId`). |

**Accepted**

HTTP **200**

```json
{
    "status": 1,
    "message": "Webhook accepted",
    "orderId": "aArg23fvas"
}
```

**Not accepted (validation or business rules)**

HTTP **400**

```json
{
    "status": 0,
    "message": "<reason>",
    "orderId": "aArg23fvas"
}
```

**Not authorized**

HTTP **401**

```json
{
    "status": 0,
    "message": "Invalid token",
    "orderId": "aArg23fvas"
}
```

#### How this fits with the Direct Topup flow

| Step                         | Who calls whom     | What it does                                        |
| ---------------------------- | ------------------ | --------------------------------------------------- |
| Validation                   | Driffle → your URL | Check player / account details before top-up.       |
| Provision (top-up)           | Driffle → your URL | Ask you to perform the top-up.                      |
| **Order status (this page)** | **You → Driffle**  | Tell us **completed** or **failed** for that order. |

#### Example (command line)

```bash
curl -sS -X POST 'https://services.driffle.com/api/seller/legacy/webhook/topup/order-status' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <YOUR_TOPUP_API_KEY>' \
  -d '{
    "orderId": "aArg23fvas",
    "status": "completed",
    "message": "Top-up credited successfully"
  }'
```

#### Checklist

* Use **`https://services.driffle.com/api/seller/legacy/webhook/topup/order-status`** (or the equivalent URL for your environment).
* Use the **Topup API key** from the seller dashboard.
* Always send a **message** for both **completed** and **failed**.
* If you retry after errors, make sure repeated calls for the same order do not cause duplicate real-world top-ups on your side.

#### Updating Your Configuration <a href="#updating-your-configuration" id="updating-your-configuration"></a>

To keep your topup service running smoothly:

* **Test your endpoints regularly** to ensure they're working
* **Monitor your API performance** to avoid cooldown periods
* **Update your API key** if needed for security
* **Check your domain verification** status periodicallyTransaction Management
* **Monitor completed transactions** in your dashboard
* **Handle refunds** through the Driffle refund system
* **Track commission fees** and earnings
* **View transaction history** and analytics

## **Managing Topup Products** <a href="#example" id="example"></a>

After enabling the Direct Topup API, you can manage your top-up products from the "Currently Selling" section of your dashboard.

1. Navigate to **My Store > Currently Selling.**
2. Select the **Direct-Topup** filter to view all your direct top-up products.
3. From here, you can see a list of all your active and in-active top-up items, including the title, last sold date, and status.

<figure><img src="/files/XeqNJYWK8FCZAJ7jtKeK" alt=""><figcaption></figcaption></figure>

**Editing Topup Denominations and Pricing**

You can manage individual denominations for each top-up product.

1. On the "Currently Selling" page, click on a top-up product to expand the view of denomination.
2. This will display a list of all available denominations for that product (e.g., Weekly Diamond, Diamonds, Twilight Pass).

<figure><img src="/files/kNtq7MwctcawNIPSQdFQ" alt=""><figcaption></figcaption></figure>

3. For each denomination, you can:

* Toggle the **Status** to make it active or inactive.
* View the number of **Declared** topups and the total number of **Topups** performed.
* Set the **Auto. Price**.
* View and **set the lowest** selling price.
* See the commission and the amount you will receive.
* Click **Edit** to modify the details of that specific denomination.

**Ready to get started?** Log in to your [seller dashboard](https://seller.driffle.com/) and navigate to Settings → Topup API to begin the setup process!\
\ <br>


---

# Agent Instructions: 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:

```
GET https://docs.driffle.com/driffle-seller-api-legacy/reference/direct-topup-webhook.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
