> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.qonversion.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Send in-app subscription and purchase events to your server with webhooks

Qonversion validates user receipts with app stores and sends subscription events to your HTTP endpoints. Keep in mind events delivery time when using webhooks to manage subscriber statuses on your back-end. Webhook delivery is asynchronous and typically completes within tens of seconds, but the exact latency depends on store-side notification timing, your server's response time, and any retries. For real-time subscription status on the client-side, use the [checkEntitlements](check-permissions) method of the Qonversion SDK.

## 1. Set up the webhook URL

1. Navigate to the Integrations section in your Qonversion account and select Webhooks.
2. Register your URL and Qonversion will send a request
3. Press the "Add new integration" or "Save" button. If the endpoint server returns a 200 response code, the integration is activated.

<img src="https://mintcdn.com/qonversion/5c527iOH0vIMjiW3/images/docs/ce45d70-Webhooks_integration.png?fit=max&auto=format&n=5c527iOH0vIMjiW3&q=85&s=342c6ad061396b90420f39274203053e" alt="" width="3432" height="1682" data-path="images/docs/ce45d70-Webhooks_integration.png" />

### Sandbox webhook URL

The Webhooks integration form also exposes a separate **Sandbox Webhook URL** field. Production-environment events are delivered to the main URL; sandbox-environment events (`environment: "sandbox"`) are delivered to the Sandbox URL when it is set. If you receive sandbox events but leave the Sandbox URL empty, Qonversion will fail to deliver them and they will be retried until the per-event tracking window expires.

## 2. Request format

Qonversion sends **POST** request to webhook URL every time an event occurs. The request includes an `Authorization` header of the form `Basic <token>`, where `<token>` is the **Header Authorization-Token Value** you configured in the Webhooks integration settings - it is sent as-is, not base64-encoded as in standard HTTP Basic auth. Use it to protect your server from unwanted requests.

<Info>
  ### SSL certificate

  Remember, maintaining secure connections is essential for the integrity and reliability of your application's communication.

  Ensure the SSL certificate used is not expired and your server's CA bundle is up-to-date to recognize the latest root CAs.
</Info>

**Request Header:**

<CodeGroup>
  ```json theme={null}
  Authorization: Basic {Header Authorization-Token}
  Accept: application/json
  ```
</CodeGroup>

**Request Body:**

<CodeGroup>
  ```json theme={null}
  {
      "event_name": "trial_converted",
      "user_id": "3YjIDEUDaf_5g4IdWw6zcMlLgfg_YQp2",
      "custom_user_id": "",
      "identity_id": "",
      "advertiser_id": "9FD1767D-8B48-45BD-A2F4-1C08B08E56F2",
      "time": 1600000000,
      "created_at": 1600000000,
      "product_id": "com.myapp.subs.9.99.trial",
      "revenue": {
          "value": 7.99,
          "value_usd": 9.99,
          "currency": "GBP",
          "is_proceed": 0,
          "proceeds_rate": 70
      },
      "price": {
          "value": 7.99,
          "value_usd": 9.99,
          "currency": "GBP"
      },
      "transaction": {
          "transaction_id": "500000601234560",
          "original_transaction_id": "500000601234560",
          "expires": 1600259200,
          "grace_period_expires": null,
        "transaction_date": 1600004000,
  			"promo_offer_id": "appname.subscription.month.withoutTrial.promo"

      },
      "properties": {
          "_q_email": "me@qonversion.io"
      },
      "device_id": "0E66565D-4F3A-E366-B3D4-B5DDAC6BBE2E",
      "app_version": "2.1.4",
      "sdk_version": "3.1.0",
      "environment": "production",
      "platform": "iOS",
      "ip": "10.0.0.1",
      "country": "GB",
      "storefront": "GBR",
      "old_product_id": "com.myapp.subs.4.99.trial",
      "new_product_id": "com.myapp.subs.9.99.trial",
      "locale": "en_US",
      "subscription_group": "784563",
      "user_install_date": 1600000000,
      "project_name": "Sample App",
      "app_id": "com.sample.app",
      "quantity": 3,
      "subscription_renew_count": 5,
      "entitlements": [
          {
              "active": true,
              "expires": 1654215637,
              "id": "plus",
              "product": {
                  "product_id": "main",
                  "subscription": {
                      "current_period_type": "regular",
                      "renew_state": "will-renew"
                  }
              },
              "source": "stripe",
              "started": 1652438020
          }
      ],
      "asa_attribution": {
          "org_id": 1234567890,
          "campaign_id": 1234567890,
          "adgroup_id": 1234567890,
          "keyword_id": 1234567890,
          "ad_id": 1234567890,
          "country_or_region": "DE",
          "conversion_type": "Download",
          "click_date": "2024-08-21T16:10Z",
   		   	"impression_date": "2024-08-21T16:10Z",
      		"claim_type": "Impression"
      }
  }
  ```
</CodeGroup>

| Column                     | Required | Description                                                                                                                                                                                                                                                                                                                        |
| -------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| event\_name                | yes      | Event name provided in the integration config. See the details on the events tracked[here](integrations-overview)                                                                                                                                                                                                                  |
| user\_id                   | yes      | Unique user identifier assigned by Qonversion                                                                                                                                                                                                                                                                                      |
| custom\_user\_id           | yes      | Unique user identifier that you can set with Qonversion SDK methods:[User Identifiers](user-identifiers#logging-in)                                                                                                                                                                                                                |
| identity\_id               | yes      | Unique user ID for the authenticated users that you can set using [identify method](user-identifiers#3-user-identity) of the Qonversion SDK                                                                                                                                                                                        |
| advertiser\_id             | yes      | IDFA or AAID                                                                                                                                                                                                                                                                                                                       |
| time                       | yes      | The time an app store changed a subscription status or a time Qonversion detected the change in the UNIX epoch time format in seconds. Read more about events time[here](integrations-overview#event-time)                                                                                                                         |
| created\_at                | yes      | The time Qonversion generated the event                                                                                                                                                                                                                                                                                            |
| product\_id                | yes      | App Store or Google Play Store product identifier                                                                                                                                                                                                                                                                                  |
| revenue                    | yes      | Dictionary with transaction revenue details. Only events with value filled                                                                                                                                                                                                                                                         |
| price                      | yes      | Dictionary containing the price details of the product                                                                                                                                                                                                                                                                             |
| transaction                | yes      | Dictionary with store transaction IDs and expiration timestamp                                                                                                                                                                                                                                                                     |
| properties                 | yes      | User properties provided by SDK as a JSON object (always present; sent as `{}` when the user has no properties). Read more about user properties [here](user-properties).                                                                                                                                                          |
| device\_id                 | yes      | identifierForVendor or Settings Secure Android ID.                                                                                                                                                                                                                                                                                 |
| app\_version               | no       | Application version.                                                                                                                                                                                                                                                                                                               |
| sdk\_version               | no       | Qonversion SDK version.                                                                                                                                                                                                                                                                                                            |
| environment                | yes      | "production" or "sandbox".                                                                                                                                                                                                                                                                                                         |
| platform                   | yes      | "iOS", "Android", or "Stripe".                                                                                                                                                                                                                                                                                                     |
| ip                         | yes      | Application device IP address.                                                                                                                                                                                                                                                                                                     |
| country                    | yes      | A two-letter code representing a country, defined by the[ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)standard, is determined on the Cloud provider's side based on the IP address of the incoming request.                                                                                                |
| storefront                 | no       | Apple App Store country code ([ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3), e.g. "CHN", "USA", "GBR"). Represents the storefront from which the transaction originated. Not the user's geographic location. Only available for iOS transactions when an App Store Connect API Certificate is configured. |
| old\_product\_id           | no       | Previous product (for product change events).                                                                                                                                                                                                                                                                                      |
| new\_product\_id           | no       | New product (for product change events).                                                                                                                                                                                                                                                                                           |
| locale                     | yes      | A two-letter code representing a device language based on the device locale.                                                                                                                                                                                                                                                       |
| subscription\_group        | yes      | `subscription_group_identifier` for iOS or Google `base_plan_id` for Android. Empty string for Stripe events.                                                                                                                                                                                                                      |
| user\_install\_date        | yes      | Timestamp when the user last installed the application.                                                                                                                                                                                                                                                                            |
| project\_name              | yes      | The project name of your app from the Qonversion dashboard.                                                                                                                                                                                                                                                                        |
| app\_id                    | yes      | Store App Id. App Store ID for iOS or Android Package Name for Android.                                                                                                                                                                                                                                                            |
| quantity                   | no       | Number of consumable in-app purchases. For non-consumable items or subscriptions, it will always return 1. Only present when the event has an associated transaction.                                                                                                                                                              |
| subscription\_renew\_count | no       | Total number of times a user's subscription has been renewed. Only present for events that carry a renewal counter (e.g. subscription renewals).                                                                                                                                                                                   |
| entitlements               | yes      | Granted user entitlements. Always present, delivered as a JSON array (`[{...}, {...}]`) when the user has entitlements; sent as `{}` when the user has no active entitlements. Entity fields are synchronised with our [public API](/reference/overview).                                                                          |
| asa\_attribution           | no       | Dictionary with Apple Search Ads attribution details. Only for events for users who were attributed with the ad.                                                                                                                                                                                                                   |

## Revenue and price fields

There are 3 fields that contain transaction details:

* The `revenue` field contains a dictionary with details depending on your integration setting *Send sales as proceed*.
* The `price` field always contains a gross price that is charged to a user.
* The `transaction` field contains params of the transaction related to the event.

### Revenue

| Column         | Required | Description                                                                                                                        |
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| value          | yes      | Value in user's currency                                                                                                           |
| value\_usd     | yes      | Value in USD                                                                                                                       |
| currency       | yes      | Three-letter ISO currency code                                                                                                     |
| is\_proceed    | yes      | 1 – if `value` and `value_usd` are net excluding app stores' commission; 0 - if values are before deducting app stores commission; |
| proceeds\_rate | yes      | 70 or 85; Proceeds rate that developer receives after deducting app stores commission.                                             |

### Price

| Column     | Required | Description                    |
| ---------- | -------- | ------------------------------ |
| value      | yes      | Value in user's currency       |
| value\_usd | yes      | Value in USD                   |
| currency   | yes      | Three-letter ISO currency code |

### Transaction

| Column                    | Required | Description                                                                                                    |
| ------------------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| transaction\_id           | yes      | Transaction\_id from App Store (e.g. 521456677817903) or Play Store (e.g. GPA.4563-9870-7648-87395)            |
| original\_transaction\_id | yes      | Transaction\_id from App Store (e.g. 521456677817903) or Play Store (e.g. GPA.4563-9870-7648-87395)            |
| expires                   | yes      | Expire timestamp for purchase, prolong or product change events, event timestamp for refund or upgrade events. |
| grace\_period\_expires    | yes      | Grace period expiration timestamp. This field returns the timestamp for the grace period expiration.           |
| transaction\_date         | yes      | Timestamp when the transaction was made.                                                                       |

<Warning>
  For the **Billing Issue**, **Trial Canceled**, **Subscription Canceled**, **Subscription Upgraded** events, the `transaction_id` field will be the same as for the previous related event. For the **Subscription Renewed**, **Subscription Downgraded**, **Subscription Product Changed** events, we're sending a newer `transaction_id`.
</Warning>

## Apple Search Ads attribution fields

You need to set up [Apple Search Ads integration](apple-search-ads) first, then we will send ASA attribution with all new events for only attributed users. The data in the table below can be found in the `asa_attribution` field.

<CodeGroup>
  ```json json theme={null}
  {
    ...
    "asa_attribution": {
      "org_id": 1234567890,
      "campaign_id": 1234567890,
      "adgroup_id": 1234567890,
      "keyword_id": 1234567890,
      "ad_id": 1234567890,
      "country_or_region": "DE",
      "conversion_type": "Download",
      "click_date": "2024-08-21T16:10Z",
      "impression_date": "2024-08-21T16:10Z",
      "claim_type": "Impression"
    }
  }
  ```
</CodeGroup>

| Column              | Required | Description                                                                                                                                              |
| ------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| org\_id             | yes      | The identifier of the Organization or Campaign group Id that owns the campaign.                                                                          |
| campaign\_id        | yes      | The unique identifier for the campaign.                                                                                                                  |
| adgroup\_id         | yes      | The identifier for the ad group.                                                                                                                         |
| keyword\_id         | no       | The identifier for the keyword.                                                                                                                          |
| ad\_id              | yes      | The identifier representing the assignment relationship between an ad object and an ad group.                                                            |
| country\_or\_region | yes      | The country or region for the campaign.                                                                                                                  |
| conversion\_type    | yes      | The type of conversion is either Download or Redownload.                                                                                                 |
| click\_date         | no       | The date and time when the user clicks an ad in a corresponding campaign. Available only if a user accepts App Tracking Transparency (ATT).              |
| impression\_date    | no       | The date and time when an ad view occurs in a corresponding Apple Search Ads campaign. Available only if a user accepts App Tracking Transparency (ATT). |
| claim\_type         | no       | The type of claim is either Impression or Click.                                                                                                         |

Learn more about fileds from [Apple AdSevices documentation](https://developer.apple.com/documentation/adservices/aaattribution/attributiontoken\(\)#Attribution-payload-descriptions).

## Retries between Qonversion and Destination Server

Qonversion increases the delivery rate to your server with retries. Retries happen automatically if your server is not responding (returns a non-2xx status, times out, or is unreachable). This substantially improves the data delivery rate. After the initial attempt fails, Qonversion schedules up to five retries spread over roughly 24 hours, then abandons the per-event delivery job. The tracking record itself is retained for 7 days.

Retries have the following schedule (delay measured from the previous attempt):

| Attempt | Delay since previous | Approx. time since first attempt |
| ------- | -------------------- | -------------------------------- |
| 1       | Immediate            | 0                                |
| 2       | 1 minute             | \~1 minute                       |
| 3       | 5 minutes            | \~6 minutes                      |
| 4       | \~3 hours 55 minutes | \~4 hours                        |
| 5       | 4 hours              | \~8 hours                        |
| 6       | 16 hours             | \~24 hours                       |

***

[Tenjin](tenjin)

[Refund Keeper](refund-keeper)
