RevenueHogdocs← back to app

SDK reference.

the wire-level api behind the optional sdks. two endpoints, one bearer key. usable from any http client.

What the SDK API is

RevenueHog needs no SDK: revenue, the live feed, metrics and alerts all work server-side from your App Store Connect key. The SDK API adds exactly one capability: user-level attribution, linking purchases to your own user ids so anonymous transaction-derived customers upgrade to real profiles. Two endpoints cover it: identify (who the user is) and attribute (which transaction belongs to them). The SDKs page shows the Swift / React Native / Kotlin call sites.

Authentication

Both endpoints authenticate with your organization's publishable key (pk_live_…, from settings → api) as a bearer token: Authorization: Bearer pk_live_…. The key is public by design: safe to ship in an app binary or call from a browser. It can only write identity/attribution data; it can never read revenue.

POST /api/sdk/v1/identify

Upserts an app user. Repeat calls merge: attributes shallow-merge into what's stored, device fields update, and the user's last-seen timestamp bumps. Anonymous pre-login ids (the SDKs send $anon_<uuid>) are ordinary user ids here.

identify
POST /api/sdk/v1/identify
Authorization: Bearer pk_live_…
Content-Type: application/json

{
  "appUserId": "user_42",          // required: your user id
  "bundleId": "com.example.app",   // required
  "platform": "ios",               // optional: "ios" | "android"
  "osVersion": "26.2",             // optional
  "deviceModel": "iPhone17,2",     // optional
  "locale": "en_US",               // optional
  "attributes": { "plan": "pro" }  // optional, flat JSON ≤ 8 KB
}

→ 200 { "ok": true, "id": "…" }

attributes must be a flat JSON object of at most 8 KB. platform accepts exactly ios or android; anything else is ignored rather than rejected. An unknown bundleId (an app not yet imported) still stores the identity, unscoped.

POST /api/sdk/v1/attribute

Links a store transaction to an app user. One transaction belongs to one user per organization, and re-POSTing the same originalTransactionId with a different appUserId moves it. That upsert is the whole aliasing mechanism: after login, the SDKs re-send earlier anonymous transactions under the real user id and history re-points automatically.

attribute
POST /api/sdk/v1/attribute
Authorization: Bearer pk_live_…
Content-Type: application/json

{
  "appUserId": "user_42",              // required
  "bundleId": "com.example.app",       // required
  "originalTransactionId": "2000000123456789", // required
  "productId": "com.example.app.pro.monthly"   // optional
}

→ 200 { "ok": true }

Android clients send the Google Play purchase token as originalTransactionId; it's stored as-is (RevenueHog ingests Apple revenue today; the mapping is kept for future Play support).

Rate limits, CORS & errors

Writes are limited to 240 requests per minute per organization. Over the limit, responses are 429 with a retry-after header (seconds). Other errors: 400 for malformed JSON or missing required fields, 401 for an invalid key. Both endpoints are idempotent in practice: the official SDKs retry with exponential backoff and queue offline, and re-sends merge rather than duplicate.

CORS is deliberately permissive (* origin, POST + OPTIONS): the publishable key is public, so browser-based callers are expected. Responses are never cached.

Versioning

The API is versioned in the path (/v1/). Fields may be added over time; existing fields won't change meaning within v1.