Summary
If you are building an app with subscriptions (aka iap), you probably know how hard it is to get the in-app subscription data gathered correctly and right where you need it.
It’s impossible to accurately track subscription events like renewals, conversions from free trials, refunds, and others on a device since most of these events happen on Apple or Google servers. A device simply does not have the data half of the time, since the app is not running while subscriptions change from one state to another on App Store or on Google Play.
So first, you need to build a backend to parse the subscription data directly from Apple or Google. And second, you need to send the data to the destinations like AppsFlyer or other attribution platforms, where you can measure your marketing performance.
![Sending your in-app subscription](https://framerusercontent.com/images/c6HbsVeJgfhLFLhiFFweDkVmNU.jpg)
What you need to know when sending the subscription data to AppsFlyer from your server
Let’s have a closer look at the eventValue parameter:
If you do not want the event to affect your revenue measurements in AppsFlyer (for example, events with no actual revenue like trial start or entering billing retry state), you need to send the empty value: "eventValue":""
If the value is not an integer (for example, $9,99/month subscription), a decimal comma should be used.
If the value is negative (i.e. refund), it should be preceded by a -.
Below are two examples from AppsFlyer documentation for
eventValue
. Note that the second example specifies if the event is renewal:
"eventValue": "{ \"af_revenue\": \"6\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\", \"af_quantity\" :\"1\" }"
Copy
"eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}",
Copy
Other parameters are not mandatory, but you’ll be better off sending the set of data as complete as possible.
A note on the eventTime
parameter. You can send out the time when an event happened. But it needs to be delivered to AppsFlyer before 02:00 AM (UTC) of the following day. Otherwise, AppsFlyer will ignore the value you sent and set the time of the actual event’s arrival to its servers.
Wrapping your data in JSON and sending POST request to Appsflyer.
When your data is ready, you need to wrap it in JSON again. Thus eventValue
will be wrapped twice.
Besides the correct data payload, you need to establish the correct HTTPS connection with the AppsFlyer server. First, build the URL with your APP_ID
appending it to the base endpoint URL: https://api2.appsflyer.com/inappevent/<APP_ID>
.
Then tune some headers: set Content-Type
to application/json
and put your API_KEY
to non-standard authentication
header. Now you are ready to POST your data!
Here is the full example of the POST request to AppsFlyer API:
HTTP POST https://api2.appsflyer.com/inappevent/<APP_ID> HTTP/1.1 headers: { authentication: '<YOUR_DEV_KEY>', Host: 'api2.appsflyer.com', Accept: 'application/json', 'Content-Type': 'application/json' } body: { "appsflyer_id":"<APPS_FLYER_ID>", "customer_user_id":"123456", "eventName":"af_subscribe", "eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}", "eventCurrency":"USD", "ip":"1.0.0.0", "eventTime":"2018-07-09 4:17:00.000", "af_events_api":"true" }
Copy
After the data is sent you need to check the result. There are three types of responses:
OK
responseError
responseNo response.
While OK
is what you want, other results will occur sometimes and you have to react accordingly. There is a number of different response codes, and some response codes correspond to multiple error messages. You can check the response codes including possible error messages here.
Some responses should be treated as fatal errors, i.e. AppsFlyer is not accepting the request. While others are non-fatal and should be scheduled for resending if you want your data to be complete. But if you assume that some event was not received by AppsFlyer and resend it, while it was actually received the first time, you are duplicating events. So the process of sending accurate and complete data without duplicates might be tricky.
An alternative solution to validate user receipts and share in-app subscription events
The described above solution shows that the process of sending subscription data to Appsflyer is a tedious one, and there are a lot of obstacles to tackle. So it’s the perfect time for a bit of self-promotion. It may be a good idea to use third-party service for a task like this. Qonversion provides the backend that validates in-app purchases with App Stores and provides simple out-of-the-box integration with AppsFlyer and many other platforms.
Give it a try by registering using the button below or let me know if you have any questions at michael@qonversion.io or @mstysin on twitter.
Resources:
You can find the complete documentation for AppsFlyer S2S API here, and some more details specific to subscription events here.
If you are building an app with subscriptions (aka iap), you probably know how hard it is to get the in-app subscription data gathered correctly and right where you need it.
It’s impossible to accurately track subscription events like renewals, conversions from free trials, refunds, and others on a device since most of these events happen on Apple or Google servers. A device simply does not have the data half of the time, since the app is not running while subscriptions change from one state to another on App Store or on Google Play.
So first, you need to build a backend to parse the subscription data directly from Apple or Google. And second, you need to send the data to the destinations like AppsFlyer or other attribution platforms, where you can measure your marketing performance.
![Sending your in-app subscription](https://framerusercontent.com/images/c6HbsVeJgfhLFLhiFFweDkVmNU.jpg)
What you need to know when sending the subscription data to AppsFlyer from your server
Let’s have a closer look at the eventValue parameter:
If you do not want the event to affect your revenue measurements in AppsFlyer (for example, events with no actual revenue like trial start or entering billing retry state), you need to send the empty value: "eventValue":""
If the value is not an integer (for example, $9,99/month subscription), a decimal comma should be used.
If the value is negative (i.e. refund), it should be preceded by a -.
Below are two examples from AppsFlyer documentation for
eventValue
. Note that the second example specifies if the event is renewal:
"eventValue": "{ \"af_revenue\": \"6\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\", \"af_quantity\" :\"1\" }"
Copy
"eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}",
Copy
Other parameters are not mandatory, but you’ll be better off sending the set of data as complete as possible.
A note on the eventTime
parameter. You can send out the time when an event happened. But it needs to be delivered to AppsFlyer before 02:00 AM (UTC) of the following day. Otherwise, AppsFlyer will ignore the value you sent and set the time of the actual event’s arrival to its servers.
Wrapping your data in JSON and sending POST request to Appsflyer.
When your data is ready, you need to wrap it in JSON again. Thus eventValue
will be wrapped twice.
Besides the correct data payload, you need to establish the correct HTTPS connection with the AppsFlyer server. First, build the URL with your APP_ID
appending it to the base endpoint URL: https://api2.appsflyer.com/inappevent/<APP_ID>
.
Then tune some headers: set Content-Type
to application/json
and put your API_KEY
to non-standard authentication
header. Now you are ready to POST your data!
Here is the full example of the POST request to AppsFlyer API:
HTTP POST https://api2.appsflyer.com/inappevent/<APP_ID> HTTP/1.1 headers: { authentication: '<YOUR_DEV_KEY>', Host: 'api2.appsflyer.com', Accept: 'application/json', 'Content-Type': 'application/json' } body: { "appsflyer_id":"<APPS_FLYER_ID>", "customer_user_id":"123456", "eventName":"af_subscribe", "eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}", "eventCurrency":"USD", "ip":"1.0.0.0", "eventTime":"2018-07-09 4:17:00.000", "af_events_api":"true" }
Copy
After the data is sent you need to check the result. There are three types of responses:
OK
responseError
responseNo response.
While OK
is what you want, other results will occur sometimes and you have to react accordingly. There is a number of different response codes, and some response codes correspond to multiple error messages. You can check the response codes including possible error messages here.
Some responses should be treated as fatal errors, i.e. AppsFlyer is not accepting the request. While others are non-fatal and should be scheduled for resending if you want your data to be complete. But if you assume that some event was not received by AppsFlyer and resend it, while it was actually received the first time, you are duplicating events. So the process of sending accurate and complete data without duplicates might be tricky.
An alternative solution to validate user receipts and share in-app subscription events
The described above solution shows that the process of sending subscription data to Appsflyer is a tedious one, and there are a lot of obstacles to tackle. So it’s the perfect time for a bit of self-promotion. It may be a good idea to use third-party service for a task like this. Qonversion provides the backend that validates in-app purchases with App Stores and provides simple out-of-the-box integration with AppsFlyer and many other platforms.
Give it a try by registering using the button below or let me know if you have any questions at michael@qonversion.io or @mstysin on twitter.
Resources:
You can find the complete documentation for AppsFlyer S2S API here, and some more details specific to subscription events here.
If you are building an app with subscriptions (aka iap), you probably know how hard it is to get the in-app subscription data gathered correctly and right where you need it.
It’s impossible to accurately track subscription events like renewals, conversions from free trials, refunds, and others on a device since most of these events happen on Apple or Google servers. A device simply does not have the data half of the time, since the app is not running while subscriptions change from one state to another on App Store or on Google Play.
So first, you need to build a backend to parse the subscription data directly from Apple or Google. And second, you need to send the data to the destinations like AppsFlyer or other attribution platforms, where you can measure your marketing performance.
![Sending your in-app subscription](https://framerusercontent.com/images/c6HbsVeJgfhLFLhiFFweDkVmNU.jpg)
What you need to know when sending the subscription data to AppsFlyer from your server
Let’s have a closer look at the eventValue parameter:
If you do not want the event to affect your revenue measurements in AppsFlyer (for example, events with no actual revenue like trial start or entering billing retry state), you need to send the empty value: "eventValue":""
If the value is not an integer (for example, $9,99/month subscription), a decimal comma should be used.
If the value is negative (i.e. refund), it should be preceded by a -.
Below are two examples from AppsFlyer documentation for
eventValue
. Note that the second example specifies if the event is renewal:
"eventValue": "{ \"af_revenue\": \"6\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\", \"af_quantity\" :\"1\" }"
Copy
"eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}",
Copy
Other parameters are not mandatory, but you’ll be better off sending the set of data as complete as possible.
A note on the eventTime
parameter. You can send out the time when an event happened. But it needs to be delivered to AppsFlyer before 02:00 AM (UTC) of the following day. Otherwise, AppsFlyer will ignore the value you sent and set the time of the actual event’s arrival to its servers.
Wrapping your data in JSON and sending POST request to Appsflyer.
When your data is ready, you need to wrap it in JSON again. Thus eventValue
will be wrapped twice.
Besides the correct data payload, you need to establish the correct HTTPS connection with the AppsFlyer server. First, build the URL with your APP_ID
appending it to the base endpoint URL: https://api2.appsflyer.com/inappevent/<APP_ID>
.
Then tune some headers: set Content-Type
to application/json
and put your API_KEY
to non-standard authentication
header. Now you are ready to POST your data!
Here is the full example of the POST request to AppsFlyer API:
HTTP POST https://api2.appsflyer.com/inappevent/<APP_ID> HTTP/1.1 headers: { authentication: '<YOUR_DEV_KEY>', Host: 'api2.appsflyer.com', Accept: 'application/json', 'Content-Type': 'application/json' } body: { "appsflyer_id":"<APPS_FLYER_ID>", "customer_user_id":"123456", "eventName":"af_subscribe", "eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}", "eventCurrency":"USD", "ip":"1.0.0.0", "eventTime":"2018-07-09 4:17:00.000", "af_events_api":"true" }
Copy
After the data is sent you need to check the result. There are three types of responses:
OK
responseError
responseNo response.
While OK
is what you want, other results will occur sometimes and you have to react accordingly. There is a number of different response codes, and some response codes correspond to multiple error messages. You can check the response codes including possible error messages here.
Some responses should be treated as fatal errors, i.e. AppsFlyer is not accepting the request. While others are non-fatal and should be scheduled for resending if you want your data to be complete. But if you assume that some event was not received by AppsFlyer and resend it, while it was actually received the first time, you are duplicating events. So the process of sending accurate and complete data without duplicates might be tricky.
An alternative solution to validate user receipts and share in-app subscription events
The described above solution shows that the process of sending subscription data to Appsflyer is a tedious one, and there are a lot of obstacles to tackle. So it’s the perfect time for a bit of self-promotion. It may be a good idea to use third-party service for a task like this. Qonversion provides the backend that validates in-app purchases with App Stores and provides simple out-of-the-box integration with AppsFlyer and many other platforms.
Give it a try by registering using the button below or let me know if you have any questions at michael@qonversion.io or @mstysin on twitter.
Resources:
You can find the complete documentation for AppsFlyer S2S API here, and some more details specific to subscription events here.
If you are building an app with subscriptions (aka iap), you probably know how hard it is to get the in-app subscription data gathered correctly and right where you need it.
It’s impossible to accurately track subscription events like renewals, conversions from free trials, refunds, and others on a device since most of these events happen on Apple or Google servers. A device simply does not have the data half of the time, since the app is not running while subscriptions change from one state to another on App Store or on Google Play.
So first, you need to build a backend to parse the subscription data directly from Apple or Google. And second, you need to send the data to the destinations like AppsFlyer or other attribution platforms, where you can measure your marketing performance.
![Sending your in-app subscription](https://framerusercontent.com/images/c6HbsVeJgfhLFLhiFFweDkVmNU.jpg)
What you need to know when sending the subscription data to AppsFlyer from your server
Let’s have a closer look at the eventValue parameter:
If you do not want the event to affect your revenue measurements in AppsFlyer (for example, events with no actual revenue like trial start or entering billing retry state), you need to send the empty value: "eventValue":""
If the value is not an integer (for example, $9,99/month subscription), a decimal comma should be used.
If the value is negative (i.e. refund), it should be preceded by a -.
Below are two examples from AppsFlyer documentation for
eventValue
. Note that the second example specifies if the event is renewal:
"eventValue": "{ \"af_revenue\": \"6\", \"af_content_type\": \"wallets\", \"af_content_id\": \"15854\", \"af_quantity\" :\"1\" }"
Copy
"eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}",
Copy
Other parameters are not mandatory, but you’ll be better off sending the set of data as complete as possible.
A note on the eventTime
parameter. You can send out the time when an event happened. But it needs to be delivered to AppsFlyer before 02:00 AM (UTC) of the following day. Otherwise, AppsFlyer will ignore the value you sent and set the time of the actual event’s arrival to its servers.
Wrapping your data in JSON and sending POST request to Appsflyer.
When your data is ready, you need to wrap it in JSON again. Thus eventValue
will be wrapped twice.
Besides the correct data payload, you need to establish the correct HTTPS connection with the AppsFlyer server. First, build the URL with your APP_ID
appending it to the base endpoint URL: https://api2.appsflyer.com/inappevent/<APP_ID>
.
Then tune some headers: set Content-Type
to application/json
and put your API_KEY
to non-standard authentication
header. Now you are ready to POST your data!
Here is the full example of the POST request to AppsFlyer API:
HTTP POST https://api2.appsflyer.com/inappevent/<APP_ID> HTTP/1.1 headers: { authentication: '<YOUR_DEV_KEY>', Host: 'api2.appsflyer.com', Accept: 'application/json', 'Content-Type': 'application/json' } body: { "appsflyer_id":"<APPS_FLYER_ID>", "customer_user_id":"123456", "eventName":"af_subscribe", "eventValue":"{\"af_revenue\":\"200\",\"af_content_id\":\"092\", \"af_content_type\": \"123\", \"renewal\":\"true\"}", "eventCurrency":"USD", "ip":"1.0.0.0", "eventTime":"2018-07-09 4:17:00.000", "af_events_api":"true" }
Copy
After the data is sent you need to check the result. There are three types of responses:
OK
responseError
responseNo response.
While OK
is what you want, other results will occur sometimes and you have to react accordingly. There is a number of different response codes, and some response codes correspond to multiple error messages. You can check the response codes including possible error messages here.
Some responses should be treated as fatal errors, i.e. AppsFlyer is not accepting the request. While others are non-fatal and should be scheduled for resending if you want your data to be complete. But if you assume that some event was not received by AppsFlyer and resend it, while it was actually received the first time, you are duplicating events. So the process of sending accurate and complete data without duplicates might be tricky.
An alternative solution to validate user receipts and share in-app subscription events
The described above solution shows that the process of sending subscription data to Appsflyer is a tedious one, and there are a lot of obstacles to tackle. So it’s the perfect time for a bit of self-promotion. It may be a good idea to use third-party service for a task like this. Qonversion provides the backend that validates in-app purchases with App Stores and provides simple out-of-the-box integration with AppsFlyer and many other platforms.
Give it a try by registering using the button below or let me know if you have any questions at michael@qonversion.io or @mstysin on twitter.
Resources:
You can find the complete documentation for AppsFlyer S2S API here, and some more details specific to subscription events here.
Start Now for Free
Or book a demo with our team to learn more about Qonversion
Start Now for Free
Or book a demo with our team to learn more about Qonversion
Start Now for Free
Or book a demo with our team to learn more about Qonversion
Read more
Read more
![Trash Panda App partners with Qonversion](https://framerusercontent.com/images/fIjbGE1BlBzu0OZK7vCihIvo.webp)
Trash Panda Maximizes App Revenue after Setting the Best Subscription Price with A/B Tests
Jul 8, 2024
Jul 8, 2024
![StyleDNA with Qonversion](https://framerusercontent.com/images/0CYKPTzYfOn6vdokDrwSoFR4c.webp)
How StyleDNA Saved 20% Development Time and Unlocked New Features
Jun 19, 2024
Jun 19, 2024
![WWDC 24 updates](https://framerusercontent.com/images/OFmq7UmE6o7QKdnnbRBNKtgo.png)
WWDC24 Updates for App Developers | What's new in Storekit 2 and App Store Server API?
Jun 17, 2024
Jun 17, 2024
![Parenting by Iben Sandahl uses Qonversion](https://framerusercontent.com/images/qJ2twjlmMxXqQ2MggeZqrVbB580.webp)
How A/B Testing with Qonversion Helped Iben Sandahl’s Parenting App Double Their Sales
Jun 13, 2024
Jun 13, 2024
![Trash Panda App partners with Qonversion](https://framerusercontent.com/images/fIjbGE1BlBzu0OZK7vCihIvo.webp)
Trash Panda Maximizes App Revenue after Setting the Best Subscription Price with A/B Tests
Jul 8, 2024
Jul 8, 2024
![StyleDNA with Qonversion](https://framerusercontent.com/images/0CYKPTzYfOn6vdokDrwSoFR4c.webp)
How StyleDNA Saved 20% Development Time and Unlocked New Features
Jun 19, 2024
Jun 19, 2024
![WWDC 24 updates](https://framerusercontent.com/images/OFmq7UmE6o7QKdnnbRBNKtgo.png)
WWDC24 Updates for App Developers | What's new in Storekit 2 and App Store Server API?
Jun 17, 2024
Jun 17, 2024