Authentication
Every request must include anAuthorization header containing your Appstack API key, as is, with no Bearer prefix. You can find your API key in the Appstack dashboard under your app settings.
- The event is recorded for the app of the key. If
platformnames the other OS of the same project (for exampleandroidwith your iOS app’s key), it is recorded for that project’s Android app. - A production key records production events. A development key records development events: use it to test your integration. Development events show in the Development view of the SDK page and in the Export API with a development key, and never reach your dashboards or your ad networks.
Track events (S2S)
Send a POST request to track installs, purchases, and other events:200 with {"status": "success"}. The event is then processed asynchronously: it usually shows up in the SDK page within a few minutes.
Request body fields
Using created_at correctly
created_at tells Appstack when the event happened, not when your server sent it. Leave it out to use the time Appstack receives the event. Appstack uses it to place the event on the user’s timeline, relative to the install, the click, and the user’s other events. A wrong value can therefore silently corrupt attribution, ordering, and reporting, with no error returned by the API.
A
created_at more than 1 hour in the past is replaced by the time Appstack receives the event, so that late events still reach your dashboards and ad networks. Send events as soon as they happen.- Use the original event time. Take the timestamp from the source of truth (the store notification, your billing provider, your database record), never from
now()at send time. - Always send UTC, in ISO 8601 with an explicit
Zsuffix (or offset). A timestamp without a timezone, or a local time labelled as UTC, shifts the event by hours and can move it before the install or into the wrong day. - Never send a future date. Check clock skew on your servers, and watch for seconds vs. milliseconds mix-ups when converting epoch values.
- Never hardcode or reuse a placeholder (such as the sample value in the request above). Every event must carry its own timestamp.
- Keep events consistent. An event should not be dated before the install it belongs to, and a retry of the same event (same
event_id) must keep the samecreated_atas the first attempt. - Replays and backfills: events older than 1 hour are recorded at the time they are received (see above), so the API is not suited to backfilling history. Contact Appstack before replaying past events.
created_at at all, and validate the values in a test environment before going live.
Event name length
Keepevent_name short and simple. Events are forwarded to advertising networks, and these networks enforce their own limits on event names. For example, Meta rejects events whose names are too long, so an overly long name may never reach the network and the conversion will not be reported there.
- Use a concise identifier such as
START_TRIALorPURCHASE, not a sentence or a description. - Don’t embed dynamic data (IDs, product names, dates, user info) in the name. Send them in
parametersinstead. - Stick to letters, digits, and underscores, and keep the naming consistent across events.
Supported event names
Useevent_type: "STANDARD" with the appropriate event_name. The following standard event names are supported:
SDK events (shared with in-app SDK and S2S):
User acquisition
LOGINSIGN_UPREGISTER
PURCHASEADD_TO_CARTADD_TO_WISHLISTINITIATE_CHECKOUTSTART_TRIALSUBSCRIBE
LEVEL_STARTLEVEL_COMPLETE
TUTORIAL_COMPLETESEARCHVIEW_ITEMVIEW_CONTENTSHARE
TRIAL_CONVERTEDSUBSCRIPTION_RENEWEDREFUNDINTRO
Any event name not listed above will be treated as a custom event. Custom events are tracked and visible in your dashboard but are not counted toward revenue metrics.
Revenue computation
The following events are used for revenue calculation:TRIAL_CONVERTEDSUBSCRIBEPURCHASESUBSCRIPTION_RENEWEDREFUNDINTRO
Matching (click ↔ install)
To associate an install with a click, the app sends a request to the deeplink match endpoint. Replace{app_id} and {appstack_id} with your values:
Planned: parameter-based matching
Appstack intends to support server-side matching where an intermediary server can run matching by sending explicit signals (for example user IP, city and region (country), and coordinates). That option is not available yet; until it ships, rely on automatic device-side data collection as described above.Personalize the user experience with attribution params
When a match succeeds, the deeplink match response returns the attribution params describing where the user came from (ad network, campaign, ad set, keywords, click IDs, and the raw network parameters). If you use the Appstack SDK instead of calling the match endpoint directly, you can read the same payload withgetAttributionParams() (see the React Native, Swift, Kotlin, and Flutter SDK pages).
Use these params to tailor the experience as early as the first launch, for example:
- Show a campaign-specific onboarding or welcome screen based on
appstack_campaign/appstack_ad. - Select a paywall variant or offer based on the acquisition source (
appstack_adnetwork,media_source). - Pre-fill or theme content from the matched keywords (
appstack_keywords). - Forward the params to partners (Superwall, RevenueCat, …) as user attributes for campaign filters.
Parameters returned by the match request / getAttributionParams()
The params are grouped into normalised Appstack values, a standard UTM value, the network click IDs, and the raw per-network parameters. Availability depends on the matched network and the data the click carried.
appstack_adnetwork is one of google, meta, tiktok, openai or x_ads, and is absent when the click carried no recognised network parameter. Any other parameter appended to the click URL is dropped, including utm_* and placement.
A no-match response returns deeplink_id: "" and query_params containing only the appstack_id you sent. The endpoint echoes appstack_id back on every response, so non-empty query_params is not proof of attribution. Use a non-empty deeplink_id as the match check. The attribution fields are optional and only worth inspecting once the match is confirmed — a matched standard link, for example, returns media_source and campaign_name but no appstack_adnetwork.
