Server-to-Server Webhooks
This guide describes how to add and configure custom server-to-server webhook.
NoteServer-to-server webhooks are available on "Expert" and "Enterprise" plans.
Apphud's webhook system for subscriptions allows you to catch the moment when a subscription event occurs. You can use this data to implement custom logic or analytics on your own server. You simply need to specify a URL for POST-request.
Webhooks are being sent as POST request to specified URL.
How to Add Webhook?
Step 1
At Apphud go to the "Integrations" section, click S2S webhooks add click New webhook:
Step 2
Enter webhook name and specify webhook URL. Events will be sent to this URL using POST-request:
Step 3
You may optionally specify Secret token that will be sent with the webhook request in the X-Apphud-Token HTTP header. Use this token to validate received payloads.
Step 4
Choose which between Production and Sandbox events to be sent via webhook:
Step 5
Enable events which you would like to receive webhooks for:
Step 6
Enable and save the integration:
Important NoteApphud sends only one request per webhook without retries.
Webhook Structure
The POST body for all webhooks follows the same structure:
{
"app": {},
"event": {},
"user": {}
}Let's look through each component of this structure.
App
This dictionary contains information about the app.
| Field | Type | Description |
|---|---|---|
app.uid | String | Apphud app ID |
app.bundle_id | String | iOS Bundle ID |
app.package_name | String | Android Package Name |
Event
This dictionary contains information about events.
| Field | Type | Description | Possible values |
|---|---|---|---|
event.id | String | Apphud event ID | |
event.created_at | Date | Date when this event was created by Apphud. | |
event.name | String | Event name | e.g. "trial_started" |
event.properties | Dictionary | A dictionary containing event properties. View the description below. | |
event.receipt | Dictionary | Apphud receipt information related to the event. View the description below. | |
event.store | String | Purchase store type |
event.properties
event.properties may contain fields below.
| Field | Type | Description | Possible values |
|---|---|---|---|
|
String |
Product ID |
|
|
String |
Depending on the event: the reason of an expiration of a subscription, the reason of refund, or product_id for billing_issue_resolved events |
|
|
String |
Local currency ISO code |
|
|
Float |
Price in USD |
|
|
Float |
Price in local currency |
|
|
Float |
Tax amount in USD |
|
|
Float |
Tax amount in local currency |
|
|
Float |
Developer proceeds in USD after Apple/Google commission and taxes, if applicable |
|
|
Float |
Developer proceeds in local currency after Apple/Google commission and taxes, if applicable |
|
|
String |
Introductory or promotional offer payment mode (iOS only) |
|
|
String |
Promotional offer ID |
|
|
String |
The increment of time that a subscription period is specified (iOS only) |
|
|
Integer |
The number of units per subscription period (iOS only) |
|
|
Boolean |
Whether the purchase was used via Family Sharing |
|
|
String |
Internal purchase identifier |
|
|
String |
Internal Apphud paywall ID |
|
|
String |
Internal Apphud placement ID |
|
|
String |
Paywall name as configured in Apphud |
|
|
String |
Paywall identifier as configured in the app / SDK |
event.receipt
event.receipt may contain the fields below.
Important NoteThis is an internal Apphud receipt model.
| Field | Type | Description |
|---|---|---|
event.receipt.id | String | Apphud receipt ID |
event.receipt.product_id | String | Product ID |
event.receipt.purchased_at | Date | Transaction date, example: 2022-03-12T09:38:38.081Z |
event.receipt.intro_period | Boolean | Is subscription in an introductory period |
event.receipt.trial_period | Boolean | Is subscription in the trial period. |
event.receipt.transaction_id | String | App Store transaction ID / Android Order ID |
event.receipt.original_transaction_id | String | App Store original transaction ID / Android Purchase Token |
event.receipt.price_usd | Float | Price in USD |
event.receipt.proceeds_usd | Float | Revenue in USD after Apple / Google commission deduction |
event.receipt.price | Float | Price in local currency |
event.receipt.proceeds | Float | Revenue in local currency after Apple / Google commission deduction |
event.receipt.currency | String | Local currency ISO code, example: USD |
event.receipt.quantity | Integer | Always 1 |
event.receipt.apple_share | Float | Store commission. It can be 0.15 or 0.3. |
User
This dictionary contains information about the user.
| Field | Type | Description |
|---|---|---|
user.created_at | String | User created date, example: `2022-03-12T09:38:38.081Z |
user.user_id | String | User ID |
user.total_spent | Float | User total spent in USD |
user.payments_count | Integer | User payments count |
user.ip | String | User IP address |
user.uid | String | Apphud user ID (browser user id) |
user.idfv | String | Device IDFV on iOS, and App Set ID on Android |
user.country_iso_code | String | User country code, example: US |
user.time_zone | String | User's current timezone, example: Asia/Jakarta |
user.language | String | User's current language, example: en |
user.internal_attribution | Object | If available, shows captures data from Web-to-App flows , Apphud Flows, and Apple Search Ads Integration. The fields set may include: status, provider, ad network, campaign, ad set, keyword, and custom1(with Click vs Impresssion info for ASA). |
user.partner_attribution | Object | Partner attribution data, if available. May include attribution provider and campaign metadata such as campaign, ad network, ad set, keyword, and status. |
user.variations[] | Array of Objects | List of Experiments (A/B tests) the user took part in. Each object may include experiment uidand name, variation_name, status, and timestamps for created_at and launched_at. |
user.paying | Boolean | Is the user currently paying or not |
user.currency_country_code | String | Country code used for currency calculations (ISO 3166-1 alpha-2) |
user.email | String | Reserved User property for email which has been assigned with Apphud SDK. |
user.name | String | Reserved User property for name which has been assigned with Apphud SDK. |
user.phone | String | Reserved User property for phone which has been assigned with Apphud SDK. |
user.age | String | Reserved User property for age which has been assigned with Apphud SDK. |
user.gender | String | Reserved User property for gender which has been assigned with Apphud SDK. |
user.properties [] | Array | Array of custom user properties which have been assigned with Apphud SDK |
user.subscriptions[] | Array | An array containing information about all subscriptions of the user. View the description below. |
user.devices[] | Array | Array of user deices. View the description below. |
user.subscriptions[]
user.subscriptions is an array containing user's subscriptions. Each element of this array is a dictionary with the following structure:
| Field | Type | Description | Possible values |
|---|---|---|---|
|
String |
Apphud subscription ID |
|
|
String |
Product ID |
|
|
String |
Subscription group name |
|
|
String |
Current subscription status |
|
|
Boolean |
Whether the subscription is currently in an introductory period |
|
|
Boolean |
Whether the subscription is currently in a trial period |
|
|
Date |
Subscription start date, example: |
|
|
Date |
Subscription expiration date, example: |
|
|
Date |
Subscription cancellation date, if cancelled, example: |
|
|
Boolean |
Whether auto-renew is enabled for the subscription |
|
|
Boolean |
Whether the subscription is in the retry billing period |
|
|
Boolean |
Whether any introductory offer, including a trial, has been used by the user |
|
|
String |
Subscription environment |
|
|
String |
Store where the subscription was purchased |
|
|
String |
Purchase type |
|
|
String |
For App Store: |
user.devices[]
user.devices[] is an array containing user's devices. Each element of this array is a dictionary with the following structure
| Field | Type | Description | Possible values |
|---|---|---|---|
|
String |
Apphud device ID |
|
|
String |
Device identifier |
|
|
String |
Device model |
|
|
String |
Device family |
|
|
String |
Device platform |
|
|
String |
Current app version on the device |
|
|
String |
Apphud SDK version used on the device |
|
|
String |
Operating system version |
|
|
String / Null |
Identifier for Advertisers (IDFA), if available |
|
|
String |
App version installed when the user first started using the app on this device |
|
|
String / Null |
Mobile carrier name, if available |
|
|
String / Null |
Push notification token, if available |
|
|
String / Null |
Identifier for Vendors (IDFV), if available |
|
|
Object / Null |
Adjust attribution data for this device, if available |
|
|
Object / Null |
AppsFlyer attribution data for this device, if available |
Webhooks Examples
Subscription Renewed
{
"app": {
"uid": "a1b2c3d4",
"bundle_id": "com.example.vpnapp",
"package_name": "com.example.vpnapp"
},
"event": {
"id": "11111111-2222-3333-4444-555555555555",
"created_at": "2026-03-03T16:33:05.619Z",
"properties": {
"usd_tax": 2.658333333333333,
"currency": "GBP",
"local_tax": 1.998333333333333,
"usd_price": 15.95,
"paywall_id": "pw_1234abcd",
"product_id": "com.example.vpnapp.monthly",
"local_price": 11.99,
"placement_id": "pl_5678efgh",
"usd_proceeds": 11.29791666666667,
"family_shared": false,
"local_proceeds": 8.492916666666666,
"product_bundle_id": "pb_90ab12cd",
"paywall_name": "Main Monthly Paywall",
"paywall_identifier": "paywall_main_monthly"
},
"store": "app_store",
"name": "subscription_renewed",
"receipt": {
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"intro_period": false,
"price_usd": 15.95,
"purchased_at": "2026-03-04T00:31:08.000Z",
"transaction_id": "500000000000001",
"original_transaction_id": "500000000000000",
"trial_period": false,
"price": 11.99,
"quantity": 1,
"apple_share": 0.15,
"proceeds_usd": 11.29791666666667,
"proceeds": 8.492916666666666,
"product_id": "com.example.vpnapp.monthly",
"currency": "GBP"
}
},
"user": {
"created_at": "2025-04-26T18:48:01.627Z",
"user_id": "USER-UUID-OBFUSCATED",
"total_spent": 176.27324951,
"payments_count": 11,
"ip": "203.0.113.42",
"uid": "user_ab12cd34",
"idfv": "IDFV-OBFUSCATED",
"country_iso_code": "GB",
"time_zone": "Europe/London",
"language": "en",
"partner_attribution": null,
"internal_attribution": {
"ad_set": "brand keywords",
"status": "Non-Organic",
"keyword": "vpn app",
"campaign": "UK_Search_Campaign",
"provider": "Apple Search Ads Integration",
"ad_network": "Apple Search Ads"
},
"variations": [],
"paying": true,
"currency_country_code": "GB",
"email": null,
"phone": null,
"name": null,
"age": null,
"gender": null,
"properties": [],
"attribution": {
"search_ads_data": {
"iad-keyword": "vpn app",
"iad-adgroup-name": "brand keywords",
"iad-campaign-name": "UK_Search_Campaign",
"iad-conversion-type": "Download",
"iad-country-or-region": "GB"
},
"search_ads_raw_data": {
"ad_id": -1,
"org_id": 1234567,
"claim_type": "Click",
"keyword_id": 1111111111,
"ad_group_id": 2222222222,
"attribution": true,
"campaign_id": 3333333333,
"conversion_type": "Download",
"country_or_region": "GB"
},
"facebook_data": null,
"tiktok_data": null,
"adjust_data": null,
"apphud_data": null
},
"subscriptions": [
{
"id": "sub_11111111-2222-3333-4444-555555555555",
"status": "regular",
"environment": "production",
"original_transaction_id": "500000000000000",
"expires_at": "2026-04-03T23:31:08.000Z",
"cancelled_at": null,
"started_at": "2025-04-26T18:48:25.000Z",
"autorenew_enabled": true,
"in_retry_billing": false,
"introductory_activated": true,
"store": "app_store",
"kind": "autorenewable",
"group": "iOS",
"product_id": "com.example.vpnapp.monthly",
"intro_period": false,
"trial_period": false
}
],
"devices": [
{
"id": "dev_11111111-2222-3333-4444-555555555555",
"device_id": "DEVICE-ID-OBFUSCATED",
"device_type": "iPhone 15 Pro",
"device_family": "iPhone",
"platform": "ios",
"app_version": "3.3.0",
"sdk_version": "3.6.2",
"os_version": "18.5",
"idfa": null,
"start_app_version": "3.0.5",
"carrier": null,
"push_token": null,
"idfv": "IDFV-OBFUSCATED",
"adjust_data": null,
"appsflyer_data": {
"af_status": "Organic",
"af_message": "organic install",
"appsflyer_id": "af_1745693274391_xxxxxx",
"is_first_launch": false
}
}
]
}
}How to Test Webhook
You can test webhooks using any service that may receive HTTP events, for example, RequestBin.com.
Step 1
Open RequestBin.com and click the "Create Request Bin" button.
Step 2
Copy Endpoint URL:
Step 3
Create new Webhook in Apphud using this URL. Make sure you selected "Sandbox" environment while configuring webhook.
Step 4
Make a test purchase on your device using Sandbox environment. You can read how to do this here. Now whenever webhook is triggered, you will see a full report on RequestBin:

Updated 6 days ago
