> For the complete documentation index, see [llms.txt](https://docs.enable3.io/enable3/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.enable3.io/enable3/tech/callback.md).

# Callback

**Callback** is the reward fulfillment mechanism used by Enable3 during reward redemption.

It is not a generic webhook. **Callback** is triggered when a user redeems a reward inside Enable3, and the final reward outcome must be produced by the administrator's system.

The callback connects Enable3’s internal reward lifecycle with the administrator's fulfillment logic:

**User → Redeem Reward → Enable3 → Callback → Admin → Result → Enable3 → User**

* Enable3 manages the redemption process, including balance handling, reward state, retries, and result storage.
* The administrator's backend is responsible for fulfilling the reward by generating or applying the actual outcome, such as a promo code, bonus, gift card, or external reward.

### When Callback Is Used <a href="#when-callback-is-used" id="when-callback-is-used"></a>

Callback is triggered **after a reward redemption request has passed Enable3 validation**.

It is used when a reward requires **admin-side fulfillment**, including:

* Generating unique promo codes
* Applying bonuses in the administrator's system
* Creating rewards through third-party providers
* Performing admin-specific business validation
* Producing the final reward payload returned to the user

{% hint style="warning" %}
If a reward is fully managed within Enable3 and does not require external fulfillment, the callback is not involved.
{% endhint %}

### Reward Redemption Flow <a href="#reward-redemption-flow" id="reward-redemption-flow"></a>

1. **User redeems a reward**\
   The user initiates reward redemption through the widget, SDK, or API.
2. **Enable3 validates the request**\
   Enable3 verifies:
   * User balance
   * Reward availability
   * Redemption eligibility
3. **Enable3 creates a redemption request**\
   A stable request identifier is generated, and the redemption enters processing state.
4. **Enable3 triggers the callback**\
   The administrator backend receives a fulfillment request with all required data.
5. **The admin's system processes the request**\
   Depending on the reward type, the administrator:
   * Generates a promo code
   * Applies a bonus
   * Calls external systems
   * Executes business validation
   * Produces the final reward payload
6. **The admin's system returns the fulfillment result**\
   The response indicates success or failure.
7. **Enable3 finalizes the reward**\
   Enable3:
   * Stores the result
   * Updates redemption status
   * Returns the final outcome to the user

### Responsibilities <a href="#responsibilities" id="responsibilities"></a>

#### Enable3 <a href="#enable3" id="enable3"></a>

Enable3 is responsible for the **reward lifecycle and system integrity**:

* Reward availability validation
* User balance validation and deduction
* Redemption request creation and tracking
* Callback triggering
* Retry handling for failed or timed-out callbacks
* Idempotency enforcement via request identifier
* Storing fulfillment results
* Returning final reward outcome to the user

Enable3 owns the **reward state and consistency guarantees**.

#### Administrator <a href="#operator" id="operator"></a>

The administrator is responsible for **reward fulfillment**:

* Generating the final reward outcome
* Applying rewards in internal systems
* Integrating with third-party providers
* Performing business-specific validation
* Returning success or failure result
* Handling duplicate requests idempotently

The admin owns the **execution of the reward outside Enable3**.

### Callback Contract (Conceptual) <a href="#callback-contract-conceptual" id="callback-contract-conceptual"></a>

The callback request provides all information required for fulfillment.

#### Request contains <a href="#request-contains" id="request-contains"></a>

* **User identifier**\
  Enable3 user ID and/or admin user ID
* **Reward identifier**\
  The reward being redeemed
* **Reward type**\
  Defines fulfillment logic (e.g. `PROMO_CODE`, `BONUS`, `EXTERNAL`)
* **Request identifier (idempotency key)**\
  A stable unique identifier used across retries
* **Reward metadata**\
  Configuration required for fulfillment

#### Response must indicate <a href="#response-must-indicate" id="response-must-indicate"></a>

* **Success**\
  Reward fulfilled\
  Includes final payload returned to the user (e.g. promo code, confirmation, external reference)
* **Failure**\
  Reward not fulfilled\
  Includes a clear failure reason

### Failure Handling and Retries <a href="#failure-handling-and-retries" id="failure-handling-and-retries"></a>

Callback execution is **not guaranteed to succeed on the first attempt**.

#### Possible failure scenarios <a href="#possible-failure-scenarios" id="possible-failure-scenarios"></a>

* Network errors
* Timeouts
* Admin backend issues
* Third-party provider failures
* Invalid fulfillment requests
* Unexpected responses

Enable3 applies a retry policy for failed or timed-out callbacks.

#### Idempotency Requirement <a href="#idempotency-requirement" id="idempotency-requirement"></a>

Retries may result in the same request being delivered multiple times.

The admin **must implement idempotent handling**:

* The same request identifier must not create multiple rewards
* The admin should store the request identifier
* Repeated requests must return the same result

#### Timeout Behavior <a href="#timeout-behavior" id="timeout-behavior"></a>

If the admin does not respond in time:

* Enable3 treats the attempt as failed or pending
* A retry may be triggered

Important:

* Timeout does not cancel the reward
* If fulfillment completes after timeout, subsequent retries must return the same result

#### Permanent Failure <a href="#permanent-failure" id="permanent-failure"></a>

If fulfillment cannot be completed after retries:

* Enable3 marks the redemption as failed
* The failure reason is stored
* The user does not receive a reward payload

Balance and reward state are handled according to Enable3 lifecycle rules.

### Reward Types <a href="#reward-types" id="reward-types"></a>

Callback behavior depends on the reward type.

#### PROMO\_CODE <a href="#promo_code" id="promo_code"></a>

* Administrator generates or retrieves a code
* Enable3 stores and displays it to the user

#### BONUS <a href="#bonus" id="bonus"></a>

* Administrator applies bonus in internal system
* Response confirms successful application

#### EXTERNAL <a href="#external" id="external"></a>

* Administrator fulfills reward via external provider
* Example providers include gift cards, Shopify, or third-party services
* Response includes final external reference or payload

#### **Request body example:**

```json
{ 
  "userId": "14813ccc-83b6-11ee-b962-0242ac120002", 
  "optionId": "97cf7320-25f0-485d-a2c9-2ae60c05574e",
  "purchaseProductId": "product123", 
  "amount": 100.00, 
  "tokenAmount": 500.00,
  "tokenRate": 5.0,
  "transactionId": "709a45bd-2b9a-452d-9ae2-a9aa479c29e6",
  "createdAt" : "2024-05-30T12:14:40.988257"
}

```

#### **Body**

<table data-header-hidden="false" data-header-sticky><thead><tr><th>Name</th><th>Type</th><th>Mandatory</th><th>Description</th></tr></thead><tbody><tr><td>userId</td><td>String</td><td>Yes</td><td>Unique user ID on the application side</td></tr><tr><td>optionId</td><td>String</td><td>No</td><td>This field will be empty in case of custom withdrawal</td></tr><tr><td>purchaseProductId</td><td>String</td><td>No</td><td>Custom value that can be assigned in the Admin dashboard</td></tr><tr><td>amount</td><td>Number</td><td>Yes</td><td>Amount in USDC</td></tr><tr><td>tokenAmount</td><td>Number</td><td>Yes</td><td>Amount in tokens</td></tr><tr><td>tokenRate</td><td>Number</td><td>Yes</td><td>Token rate</td></tr><tr><td>transactionId</td><td>String</td><td>Yes</td><td>Unique transaction ID from Enable3. Available in the Admin dashboard</td></tr><tr><td>createdAt</td><td>String</td><td>Yes</td><td>Date and time when the user requested withdrawal. Format: <code>yyyy-MM-dd'T'HH:mm:ss.SSSSSS</code></td></tr></tbody></table>

The callback request will be signed and contains `X-REQUEST-SIGNATURE` header.

An example of how to get the signature of the request body using secret:

#### **For Java**

```java
public String getSignature(String requestBody, String secret) {
    String md5Hex = DigestUtils.md5Hex(requestBody);
    try {
        Mac shaHMAC = Mac.getInstance("HmacSHA512");
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA512");
        shaHMAC.init(secretKey);
        return Base64.getEncoder().encodeToString(shaHMAC.doFinal(md5Hex.getBytes()));
    } catch (GeneralSecurityException ex) {
        log.error(ex.getMessage(), ex);
        throw new RuntimeException("Request signing error", ex);
    }
}
```

#### For Node JS

```javascript
const crypto = require('crypto');
function getSignature(requestBody, secret) {
  const md5Hex = crypto.createHash('md5').update(requestBody).digest('hex');
  const hmac = crypto.createHmac('sha512', secret);
  const signature = hmac.update(md5Hex).digest('base64');
  return signature;
}
const requestBody = 'your_request_body';
const secret = 'your_secret_key';
const signature = getSignature(requestBody, secret);
console.log(signature); 
```

### Key Integration Notes <a href="#key-integration-notes" id="key-integration-notes"></a>

* Callback is a **core part of reward redemption**, not a generic webhook
* It is triggered only after Enable3 validation
* The administrator must produce the **final user-facing reward result**
* The request identifier must be treated as an **idempotency key**
* Duplicate requests must not create duplicate rewards
* Enable3 manages lifecycle, balance, retries, and storage
* The admin manages fulfillment, business logic, and external integrations
* Retry and timeout behavior must be expected and handled
* The final reward shown to the user comes from the admin response
