# AppsFlyer Webhooks

AppsFlyer's **Push API** (raw data streaming) sends each attributed install and
in-app event to your server as a raw-data record, in near real time. Choose
**POST**: with GET, AppsFlyer puts the data in the query string.

## When to Use This Skill

* How do I receive AppsFlyer Push API webhooks?
* How do I authenticate / verify an AppsFlyer webhook?
* Why is my AppsFlyer authorization header check failing?
* How do I handle `install` and `af_purchase` events?
* How do I deduplicate AppsFlyer raw-data records?

## No Signature: Custom Authorization Header Only

AppsFlyer **does not sign payloads**. There is no signature header, no HMAC and
no timestamp. Instead you configure a **custom authorization header** (a header
name and a token value) per app ID in the Push API settings, and AppsFlyer sends
it on every request. Your endpoint compares the received value to the token you
stored, in constant time.

| What | Value |
| --- | --- |
| Header name | Whatever you configured (this skill defaults to `Authorization`; env `APPSFLYER_AUTH_HEADER_NAME`) |
| Header value | The token you configured (env `APPSFLYER_AUTH_TOKEN`), compared as the **full** value |
| Method | POST with a JSON raw-data record |

Tokens are set **per app ID**. If you stream several apps, either use one token
for all of them or look up the expected token by `app_id` after parsing.

## Verification (core)

```javascript
const crypto = require('crypto');

// AppsFlyer sends the header name/value you configured. No HMAC, no signature.
function verifyAppsflyerToken(received, expected) {
  if (!received || !expected) return false;            // fail closed
  const a = Buffer.from(received, 'utf8');
  const b = Buffer.from(expected, 'utf8');
  return a.length === b.length && crypto.timingSafeEqual(a, b); // length guard first
}

// Express: req.headers[(process.env.APPSFLYER_AUTH_HEADER_NAME || 'authorization').toLowerCase()]

```

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/appsflyer-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/appsflyer-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/appsflyer-webhooks/examples/fastapi/).

AppsFlyer has no SDK with a webhook verification helper, so every example does
this compare directly (`crypto.timingSafeEqual` in Node, `hmac.compare_digest`
in Python). Authenticate before you parse the JSON body.

## Common Event Types

The event name is the record's `event_name` field.

| `event_name` | Meaning |
| --- | --- |
| `install` | An attributed install |
| `af_purchase` | Standard in-app purchase event |
| `af_complete_registration` | Standard in-app registration event |
| *your own event name* | In-app events are named by your app, so the set differs per app |

Every record includes `appsflyer_id`, `app_id` and `event_time`. There is no
unique event ID, so build an idempotency key from `appsflyer_id`, `event_name`
and `event_time`. See [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/appsflyer-webhooks/references/overview.md).

## Environment Variables

```bash
APPSFLYER_AUTH_TOKEN=your_shared_secret_token     # the header value you configured
APPSFLYER_AUTH_HEADER_NAME=Authorization          # the header name you configured

```

With no token set, the examples reject every request with a 500 rather than
accept unauthenticated webhooks.

## Local Development

```bash
npx hookdeck-cli listen 3000 appsflyer --path /webhooks/appsflyer

```

No account required — the CLI creates a guest account on first run and gives
you a public HTTPS URL plus a web UI for inspecting requests (including your
custom header). Use port `8000` for the FastAPI example.

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/appsflyer-webhooks/references/overview.md) — Push API, event names, payload fields
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/appsflyer-webhooks/references/setup.md) — Configuring Push API and the authorization header
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/appsflyer-webhooks/references/verification.md) — Header compare in detail, gotchas, debugging