RevenueHogdocs
API

Authentication

How RevenueHog authenticates API calls with App Attest device tokens, the unverified quarantine path, rh_ API keys, sessions and signed store notifications.

RevenueHog uses a different credential for each kind of caller. Nothing secret ever ships in your app binary.

CallerCredentialHeader
iOS app with the Swift SDKApp Attest device tokenAuthorization: Bearer dt_…
Android, React Native, simulator, raw HTTPNone (quarantine path)none
Your servers, writing feedbackAPI keyAuthorization: Bearer rh_live_… or rh_test_…
Dashboard, mobile app, terminal toolsSessionSession cookie or Authorization: Bearer <session token>
Apple, Google, StripeURL token plus signaturePer provider

Device tokens (App Attest)

The SDK API has no API key. An iOS install proves it is your genuine app:

  1. POST /api/sdk/v1/attest/challenge returns a single-use challenge (base64url, 5 minute TTL).
  2. The app attests a key with Apple against the challenge.
  3. POST /api/sdk/v1/attest with keyId, attestation, challenge and bundleId. RevenueHog verifies the attestation offline, consumes the challenge, and finds the app whose <teamId>.<bundleId> hash matches the attested RP ID. The team ID comes from RevenueHog's own App Store Connect data, never from the client. If two workspaces match, the app wired for server notifications wins, then the oldest.
  4. The response carries deviceToken (dt_ plus 32 hex characters).

Tokens are stored hashed (SHA-256). A token binds workspace and app, so the body's bundleId is not trusted on attested calls (a mismatch is only logged). Re-enrolling a key the workspace already has rotates its token.

Enrolled devices are listed under Settings > SDK DEVICES with their app, environment (prod or sandbox) and last-seen time. Revoke deletes the row: the token stops resolving immediately and the app re-enrolls on next launch, or runs unattested if it cannot.

An unknown dt_ token gets 401 { "error": "invalid device token" }. This is the one SDK auth failure that is an error rather than a drop; the Swift SDK clears its token and re-enrolls once.

The quarantine path (unattested)

Requests with no device token are still accepted. RevenueHog resolves the bundleId:

  • An Android write (platform: "android") looks for a Google Play app with that package first, then an App Store app with the same ID. Every other write resolves App Store apps only.
  • Exactly one match: the write is stored with attested = false and labeled unverified in the dashboard.
  • No match, or more than one workspace with that bundle ID: the write is accepted with 200 { "ok": true } and dropped. A wrong bundle ID therefore looks like success; verify in the dashboard.

A malformed Authorization header that is not a dt_ token is treated as no token. The X-RevenueHog-Unattested header the Swift SDK sends is allowed by CORS but not used by the server.

On /api/sdk/v1/attribute, a valid StoreKit 2 jws upgrades the transaction link to verified even on this path.

API keys

Server-to-server feedback writes need an API key. Keys look like rh_live_<43 base64url characters> or rh_test_…, are created under Settings > API KEYS, and are shown once. See API keys.

Sessions

Management endpoints (/api/settings/*, /api/mobile/paywall, /api/export/revenue) use your RevenueHog session: the browser cookie, or Authorization: Bearer <session token> as the mobile app and the terminal device-flow login send. Sessions are workspace-scoped. A missing or invalid session returns 401 { "error": "unauthorized" }. Session tokens expire and must never go into a repository or CI secret.

Store notifications

Each connection has a unique URL token. Apple notifications are verified against Apple's root certificates and the app's bundle ID; Google Pub/Sub pushes carry an OIDC token; Stripe events are checked with the webhook signing secret. See Server-to-server.

Last updated on

On this page