> ## Documentation Index
> Fetch the complete documentation index at: https://docs.earnos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversion API

> Server-to-server postback endpoint for reporting conversion events (installs, signups, purchases, in-app milestones) to EarnOS.

## How It Works

1. A user taps an EarnOS offer link — we generate a **click ID** and pass it to your platform via your tracking URL template (e.g. `sub1`, `custom_1`, `aff_sub`, etc.)
2. The user completes an action on your platform (install, purchase, reaches a level, etc.)
3. Your server sends a **postback** to your dedicated EarnOS callback endpoint with the click ID and event details
4. EarnOS validates the postback, matches it to the user, and processes the reward

***

## Your Callback Endpoint

Each provider receives a dedicated endpoint:

```
https://api.earnos.com/conversion/v1/providers/{your_slug}/callback
```

Your `slug` is assigned during onboarding (e.g. `ayet`, `affise`, `tune`). Both **GET** and **POST** methods are accepted.

The endpoint returns **200 OK** immediately — processing happens asynchronously.

```json theme={null}
{
  "status": "accepted",
  "requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
```

***

## Parameters

Parameters can be sent as **query string** (GET) or **JSON body** (POST). The exact parameter names depend on your platform's adapter — we support aliases for all major networks.

### Required

<ParamField query="click_id" type="string" required>
  The EarnOS click ID provided to you via the tracking URL. Depending on your platform this may be passed as `click_id`, `custom_1`, `sub1`, `aff_sub`, `clickid`, or `external_identifier`.
</ParamField>

<ParamField query="event_name" type="string" required>
  The event type, e.g. `install`, `tutorial_complete`, `level_achieved_10`, `purchase`. Must match the event names configured for your campaign in EarnOS.
</ParamField>

<ParamField query="transaction_id" type="string" required>
  Your unique transaction/conversion ID for this event. Used for deduplication — sending the same `transaction_id` twice will be treated as a duplicate. Aliases: `event_id`, `conversion_id`, `action_id`, `tid`.
</ParamField>

### Optional

<ParamField query="payout_amount" type="string">
  Payout amount, e.g. `"2.50"`. Aliases: `payout_usd`, `payout`, `amount`, `sum`, `currency_amount`.
</ParamField>

<ParamField query="payout_currency" type="string" default="USD">
  ISO currency code. Defaults to `USD` when `payout_usd` is used.
</ParamField>

<ParamField query="occurred_at" type="string">
  When the event occurred. Accepts ISO 8601, unix timestamp (seconds or milliseconds). Aliases: `callback_ts`, `datetime`, `ts`, `timestamp`.
</ParamField>

<ParamField query="launch_id" type="string">
  EarnOS launch tracking ID (provided in your tracking URL template). Aliases: `custom_2`, `launchId`, `aff_sub2`, `sub2`.
</ParamField>

<ParamField query="launch_identity" type="string">
  EarnOS launch identity (provided in your tracking URL template). Aliases: `custom_3`, `launchIdentity`, `aff_sub3`, `sub3`.
</ParamField>

<ParamField query="offer_id" type="string">
  Your internal offer/campaign identifier.
</ParamField>

<ParamField query="status" type="string" default="confirmed">
  Conversion status. Use `is_chargeback=1` or `status=reversed` to report chargebacks/reversals.
</ParamField>

***

## Authentication

Authentication is configured per-provider during onboarding. We support multiple verification methods to match your platform's capabilities.

### HMAC-SHA256 Query Signature (Recommended)

Sign the query string using HMAC-SHA256 with your shared secret. The signature can be sent as a **header** or **query parameter** depending on your configuration.

**Signature computation (sorted query):**

```javascript theme={null}
const crypto = require('crypto');

// 1. Sort all query params alphabetically (exclude signature param)
const sortedParams = new URLSearchParams(
  [...url.searchParams.entries()]
    .filter(([key]) => key !== 'signature')
    .sort(([a], [b]) => a.localeCompare(b))
);

// 2. Compute HMAC-SHA256
const signature = crypto
  .createHmac('sha256', 'your_shared_secret')
  .update(sortedParams.toString())
  .digest('hex');

// 3. Attach as header or query param (per your config)
```

### API Key

Include your API key as a header or query parameter:

```
X-Api-Key: your_api_key
```

### HMAC-SHA256 Body Signature

For POST requests with JSON bodies:

```
X-Signature: HMAC-SHA256(timestamp + "." + body, secret)
X-Timestamp: unix_timestamp
```

Timestamps must be within 5 minutes of server time.

### IP Allowlist

Callbacks are only accepted from your registered IP addresses. No signature required.

### Other Methods

We also support **Timestamped Token**, **Affise S2S**, and **Signed Redirect** (including Dynata-specific) verification. Contact your partner manager for configuration details.

***

## Examples

### GET — Install Event (Query String)

```bash theme={null}
curl "https://api.earnos.com/conversion/v1/providers/your_slug/callback?\
click_id=550e8400-e29b-41d4-a716-446655440000&\
event_name=install&\
transaction_id=txn_abc123&\
payout_usd=2.00"
```

### POST — Purchase Event (JSON Body)

```bash theme={null}
curl -X POST https://api.earnos.com/conversion/v1/providers/your_slug/callback \
  -H "X-Api-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "click_id": "550e8400-e29b-41d4-a716-446655440000",
    "event_name": "purchase",
    "transaction_id": "order_12345",
    "payout_usd": "5.00"
  }'
```

### Multiple Events (Same Click)

A single click can have multiple events — common for milestone-based offers. Each event needs a unique `transaction_id`:

```bash theme={null}
# Step 1: Install
curl "https://api.earnos.com/conversion/v1/providers/your_slug/callback?\
click_id=550e8400&event_name=install&transaction_id=txn_install_789&payout_usd=2.00"

# Step 2: Tutorial complete
curl "https://api.earnos.com/conversion/v1/providers/your_slug/callback?\
click_id=550e8400&event_name=tutorial_complete&transaction_id=txn_tutorial_789&payout_usd=3.00"

# Step 3: Reach level 10
curl "https://api.earnos.com/conversion/v1/providers/your_slug/callback?\
click_id=550e8400&event_name=level_achieved_10&transaction_id=txn_level10_789&payout_usd=5.00"
```

***

## Response

All requests return **200 OK** immediately. Processing is asynchronous.

<ResponseExample>
  ```json 200 - Accepted theme={null}
  {
    "status": "accepted",
    "requestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
  }
  ```
</ResponseExample>

Duplicate events (same `transaction_id`) are silently deduplicated — you will still receive a 200 response.

***

## Error Codes

| HTTP Code | Error                    | Meaning                                | Action              |
| --------- | ------------------------ | -------------------------------------- | ------------------- |
| 400       | `INVALID_CLICK_ID`       | Click ID not found or expired          | Do not retry        |
| 400       | `CLICK_PARTNER_MISMATCH` | Click belongs to a different provider  | Verify click source |
| 400       | `EVENT_NOT_ALLOWED`      | Event name not configured for campaign | Contact EarnOS      |
| 401       | `SIGNATURE_REQUIRED`     | No signature provided                  | Add authentication  |
| 401       | `INVALID_SIGNATURE`      | Signature verification failed          | Check secret key    |
| 401       | `TIMESTAMP_EXPIRED`      | Timestamp outside 5-minute window      | Sync server clock   |
| 404       | `PROVIDER_NOT_FOUND`     | Unknown provider slug                  | Verify endpoint URL |
| 503       | `SERVICE_UNAVAILABLE`    | Temporary error                        | Retry with backoff  |

### Retry Logic

* **200**: Accepted — do not retry
* **400**: Client error — do not retry (fix the request)
* **401**: Auth error — do not retry (fix credentials)
* **503**: Server error — retry with exponential backoff

Recommended retry schedule: 1s, 5s, 30s, 2min, 10min, 1hr (then alert).

***

## Tracking URL Parameters

During onboarding, EarnOS configures your tracking URL template with the following values in your platform's sub-parameter slots:

| EarnOS Value      | Purpose                           | Common Slot Names                        |
| ----------------- | --------------------------------- | ---------------------------------------- |
| `click_id`        | Links the postback to the user    | `sub1`, `custom_1`, `aff_sub`, `clickid` |
| `launch_id`       | Tracks the app launch session     | `sub2`, `custom_2`, `aff_sub2`           |
| `launch_identity` | Provider-specific launch identity | `sub3`, `custom_3`, `aff_sub3`           |

Your postback must include at least the `click_id` value so we can attribute the conversion.

***

## Event Names

Event names are configured per-campaign during onboarding. Common examples:

| Event               | Description                     |
| ------------------- | ------------------------------- |
| `install`           | App installed / account created |
| `tutorial_complete` | Completed onboarding tutorial   |
| `level_achieved_10` | Reached level 10                |
| `level_achieved_25` | Reached level 25                |
| `purchase`          | Made an in-app purchase         |
| `signup`            | Completed registration          |
| `subscription`      | Started a subscription          |

Event names must match exactly as configured. Contact your EarnOS partner manager for the list of events configured for your campaign.

***

## Testing

### Verification Checklist

1. **Verify click\_id capture**: Ensure your tracking template correctly captures the EarnOS click ID
2. **Send test postback**: Use a real click\_id from a test session
3. **Check response**: Confirm you receive `200 OK`
4. **Verify in EarnOS**: Confirm the conversion appears in the EarnOS dashboard
5. **Test duplicate handling**: Send the same postback again — it should be silently deduplicated
6. **Test all event types**: Send each configured event name to verify the full flow

***

## FAQ

**Q: What's the attribution window?**
A: 7 days by default. Postbacks for clicks older than 7 days will be rejected.

**Q: What happens if I send a duplicate?**
A: Duplicates are silently deduplicated based on `transaction_id`. You'll still receive a 200 response.

**Q: Can I send multiple events for the same click?**
A: Yes. Each event needs a unique `transaction_id`. This is standard for milestone-based campaigns (e.g. install, then tutorial, then level 10).

**Q: How quickly are rewards processed?**
A: Postbacks are processed within seconds. Reward payout timing depends on the campaign configuration.

**Q: Do you support chargebacks/reversals?**
A: Yes. Send a postback with `is_chargeback=1` or `status=reversed` using the same click\_id. This must be enabled for your account.

***

## Support

* **Integration issues**: Contact your EarnOS partner manager
* **Technical questions**: [support@earnos.io](mailto:support@earnos.io)
