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

# API reference

The Amply SDK reaches the backend over a small, signed HTTPS API. Your app never calls these endpoints itself — the SDK handles the request shape, authentication and retries. This page is here so you can see what leaves the device during an integration audit or a security review.

## At a glance

| Method | Path                  | Purpose                                                                 |
| ------ | --------------------- | ----------------------------------------------------------------------- |
| POST   | `/api/v1/session`     | Report sessions, events, and user/device state. The main data channel.  |
| POST   | `/api/v1/attribution` | Report install-attribution data from third-party attribution providers. |
| POST   | `/api/v1/tm/apple`    | Report Apple App Store in-app purchase transactions.                    |

**Base URL:** `https://api.amply.tools`

All endpoints accept and return JSON (`Content-Type: application/json`).

***

## Authentication

Every request identifies your application via `X-Api-Key`, your application's public API key. Session requests are additionally signed, and the SDK does that for you — there is nothing to configure and nothing to compute.

Both the public and secret API keys are issued in your Amply dashboard under the application's settings. You give both to the SDK when you initialise it; that is all either key is for.

### Application lookup

The backend locates your application from `X-Api-Key`. If the key is unknown or the application has been deleted, every endpoint returns `404 Not Found` with the body `{"detail": "Application not found"}`.

***

## POST /api/v1/session

Reports one or more sessions along with their events. This is the endpoint the SDK calls when it flushes its queue.

### Request

```
POST /api/v1/session HTTP/1.1
Host: api.amply.tools
Content-Type: application/json
X-Api-Key: <public key>

{ ... }
```

### Request body

```json
{
  "user": {
    "id": "u_abc123",
    "lastSyncTS": 1714000000,
    "properties": [
      { "name": "plan", "value": "pro" }
    ]
  },
  "device": {
    "id": "d_xyz789",
    "properties": {
      "sdkVersionNormalized": 10203,
      "osVersionNormalized": 170400,
      "appVersionNormalized": 20100,
      "appInstallVersionNormalized": 20000,
      "platform": "iOS",
      "deviceModel": "iPhone15,3",
      "vendorIdentifier": "B1D…",
      "installDatetime": 1713900000,
      "adId": "D4B…",
      "country": "US"
    }
  },
  "sessions": [
    {
      "id": "s_001",
      "number": { "global": 42, "version": 3 },
      "startDate": "2026-04-24T10:00:00+00:00",
      "finishDate": "2026-04-24T10:05:12+00:00",
      "events": [
        {
          "id": "e_001",
          "name": "PurchaseCompleted",
          "type": "custom",
          "timestamp": 1714000200,
          "date": "2026-04-24T10:03:20+00:00",
          "params": [
            { "name": "sku",   "value": "premium_yearly" },
            { "name": "price", "value": 59.99 }
          ]
        }
      ]
    }
  ]
}
```

#### Top-level fields

| Field      | Type   | Required | Description                                                   |
| ---------- | ------ | -------- | ------------------------------------------------------------- |
| `user`     | object | yes      | User identity and custom properties.                          |
| `device`   | object | yes      | Device identity and collected device properties.              |
| `sessions` | array  | yes      | One or more session records. Must contain at least one entry. |

#### `user`

| Field        | Type                     | Required | Description                                                              |
| ------------ | ------------------------ | -------- | ------------------------------------------------------------------------ |
| `id`         | string \| null           | no       | Your application's user identifier, if set via `setUserId(...)`.         |
| `lastSyncTS` | number \| null           | no       | Unix seconds of the last successful sync, used for delta reconciliation. |
| `properties` | array of `{name, value}` | no       | Custom user properties. `value` is `string`, `number`, or `boolean`.     |

#### `device`

| Field        | Type   | Required | Description                                   |
| ------------ | ------ | -------- | --------------------------------------------- |
| `id`         | string | yes      | Stable device identifier assigned by the SDK. |
| `properties` | object | yes      | Device metadata.                              |

`device.properties`:

| Field                         | Type           | Required | Description                                                           |
| ----------------------------- | -------------- | -------- | --------------------------------------------------------------------- |
| `sdkVersionNormalized`        | number         | yes      | SDK version encoded as a comparable integer.                          |
| `osVersionNormalized`         | number         | yes      | OS version encoded as a comparable integer.                           |
| `appVersionNormalized`        | number         | yes      | Current app version encoded as a comparable integer.                  |
| `appInstallVersionNormalized` | number         | yes      | App version at install time, encoded as a comparable integer.         |
| `platform`                    | string         | yes      | `"iOS"` or `"Android"`.                                               |
| `deviceModel`                 | string         | yes      | Device model identifier (for example, `iPhone15,3`).                  |
| `vendorIdentifier`            | string         | yes      | Vendor-scoped device identifier (IDFV on iOS, equivalent on Android). |
| `installDatetime`             | number         | yes      | Unix seconds of the first install.                                    |
| `adId`                        | string \| null | no       | Advertising identifier, if available and permitted.                   |
| `country`                     | string \| null | no       | ISO country code, if resolved.                                        |

#### `sessions[*]`

| Field        | Type                      | Required | Description                                                                                                                                   |
| ------------ | ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`         | string                    | yes      | Unique session identifier generated by the SDK.                                                                                               |
| `number`     | object                    | yes      | `{ "global": <int>, "version": <int> }` — `global` counts sessions for this device, `version` counts sessions within the current app version. |
| `startDate`  | string (ISO 8601)         | yes      | Session start, with timezone offset.                                                                                                          |
| `finishDate` | string (ISO 8601) \| null | no       | Session end. Null if the session is still open at flush time.                                                                                 |
| `events`     | array                     | no       | Events captured during the session. May be empty.                                                                                             |

#### `sessions[*].events[*]`

| Field       | Type                     | Required | Description                                                    |
| ----------- | ------------------------ | -------- | -------------------------------------------------------------- |
| `id`        | string                   | yes      | Event identifier generated by the SDK.                         |
| `name`      | string                   | yes      | Event name.                                                    |
| `type`      | string                   | yes      | `"custom"` or `"system"`.                                      |
| `timestamp` | number                   | yes      | Unix seconds when the event was recorded.                      |
| `date`      | string (ISO 8601)        | yes      | Same instant as `timestamp`, rendered as an ISO string.        |
| `params`    | array of `{name, value}` | yes      | Event properties. `value` is `string`, `number`, or `boolean`. |

### Successful response

```
HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 24 Apr 2026 10:05:13 GMT

{}
```

The SDK reads the server time from the response `Date` header and uses it to correct clock skew on the device. If the header is missing or unparseable, the SDK logs a warning but treats the request as failed for clock-sync purposes.

### Error responses

| Status                     | Meaning                                                                       |
| -------------------------- | ----------------------------------------------------------------------------- |
| `403 Forbidden`            | The request could not be authenticated for this API key.                      |
| `404 Not Found`            | The application for this API key does not exist.                              |
| `422 Unprocessable Entity` | Request body failed validation. The response body lists the offending fields. |
| `5xx`                      | Server-side error. The SDK retries with exponential backoff.                  |

Example validation error:

```json
{
  "error":   "validation_failed",
  "status":  422,
  "message": "Request body failed validation.",
  "fields": [
    {
      "path":    "sessions[0].events[0].name",
      "message": "Event name must not be blank."
    }
  ]
}
```

***

## POST /api/v1/attribution

Reports install-attribution data from third-party attribution providers.

### Request body

```json
{
  "device": {
    "id": "d_xyz789",
    "external_id": "ext-abc"
  },
  "system": {
    "os_version": "17.4"
  },
  "attribution": {
    "adjust": {},
    "apple_search_ads": {
      "orgId": 123456,
      "campaignId": 789,
      "conversionType": "Download",
      "clickDate": "2026-04-23",
      "adGroupId": 456,
      "countryOrRegion": "US",
      "keywordId": 42,
      "adId": 1001
    },
    "apps_flyer": {}
  },
  "custom": {}
}
```

| Field                          | Type           | Required | Description                                                                                       |
| ------------------------------ | -------------- | -------- | ------------------------------------------------------------------------------------------------- |
| `device`                       | object         | yes      | Device identity. `id` is required; `external_id` is optional.                                     |
| `system`                       | object         | yes      | Device system information. Must include `os_version`.                                             |
| `attribution`                  | object         | yes      | Container for per-provider payloads. Unused providers may be omitted or sent as `{}`.             |
| `attribution.adjust`           | object \| null | no       | Adjust attribution payload. Pass-through; schema follows Adjust's attribution response.           |
| `attribution.apple_search_ads` | object \| null | no       | Apple Search Ads attribution. See table below.                                                    |
| `attribution.apps_flyer`       | object \| null | no       | AppsFlyer attribution payload. Pass-through; schema follows AppsFlyer's conversion-data response. |
| `custom`                       | object \| null | no       | Arbitrary custom-attribution object. Stored as-is.                                                |

#### `attribution.apple_search_ads`

All fields are optional. Copy the values verbatim from the Apple Search Ads attribution API response.

| Field             | Type                        |
| ----------------- | --------------------------- |
| `orgId`           | number                      |
| `campaignId`      | number                      |
| `conversionType`  | string                      |
| `clickDate`       | string (date, `YYYY-MM-DD`) |
| `adGroupId`       | number                      |
| `countryOrRegion` | string                      |
| `keywordId`       | number                      |
| `adId`            | number                      |

### Successful response

```
HTTP/1.1 200 OK
Content-Type: application/json

{}
```

### Error responses

| Status                     | Meaning                                              |
| -------------------------- | ---------------------------------------------------- |
| `404 Not Found`            | Missing/invalid `X-Api-Key`, or unknown application. |
| `422 Unprocessable Entity` | Validation failed.                                   |
| `5xx`                      | Server-side error; safe to retry.                    |

Note: this endpoint does not require request signing or replay protection at present.

***

## POST /api/v1/tm/apple

Reports Apple App Store in-app purchase transactions for a device. Send one request per batch of transactions. Each request must include at least one transaction.

### Request body

```json
{
  "device": {
    "id": "d_xyz789",
    "external_id": "ext-abc"
  },
  "transactions": [
    { "id": "2000000123456789" },
    { "id": "2000000123456790" }
  ]
}
```

| Field                | Type   | Required | Description                                                                           |
| -------------------- | ------ | -------- | ------------------------------------------------------------------------------------- |
| `device`             | object | yes      | Device identity. `id` required; `external_id` optional.                               |
| `transactions`       | array  | yes      | One entry per transaction. Must contain at least one item.                            |
| `transactions[*].id` | string | yes      | The transaction ID returned by StoreKit (`originalTransactionId` or `transactionId`). |

The server calls Apple's App Store Server API to fetch the signed transaction and entitlement details, so only the ID is needed in the payload.

### Successful response

```
HTTP/1.1 200 OK
Content-Type: application/json

{}
```

### Error responses

| Status                     | Meaning                                                             |
| -------------------------- | ------------------------------------------------------------------- |
| `404 Not Found`            | Missing/invalid `X-Api-Key`, or unknown application.                |
| `422 Unprocessable Entity` | `transactions` was missing or empty, or a transaction ID was blank. |
| `5xx`                      | Server-side error; safe to retry.                                   |

***

## Idempotency

A session upload that reaches the server twice — after a dropped connection, say — is counted once. The SDK handles this; nothing is required of your app, and a retry never duplicates a user's events.

## Rate limits

No per-endpoint rate limit is enforced today. Apps are expected to batch events — the SDK does this automatically by buffering events and flushing on a schedule rather than per call.

## Retries

* Retry `5xx` and network-level failures with exponential backoff.
* Do not retry `4xx` without fixing the cause — they indicate malformed payloads, expired keys, or a conflicting request ID.
* The SDK keeps unsent events on disk until a successful `2xx` response, so a failed flush does not lose data.

***

## Related

* [Events reference](/reference/events.md) — event names, types, and property conventions.
* [SDK reference — iOS](/reference/sdk-ios.md) — the client-side entry points that call these endpoints.
* [SDK reference — Android](/reference/sdk-android.md) — same for Android.
