Purchasely
2.8
2.8
  • Welcome page
  • General
    • Presentation
  • Quick test
    • Test in 5 minutes
  • Basic configuration
    • Console Configuration
      • Creating a new application
      • Creating your Products
        • App Store
        • Play Store
        • Huawei App Gallery
        • Amazon App Store
        • Products & Plans
      • Design your Paywalls
    • SDK installation
      • iOS SDK
      • Android SDK
      • React Native SDK
      • Cordova SDK
    • SDK configuration
    • Webhook
      • Receiving and understanding messages
      • Managing entitlements
      • Subscription events
      • Events attributes
      • Detailed sequence diagrams
    • Observer mode
  • Dashboards
    • Introduction
    • Live
    • Subscriptions
    • Cohorts
    • Trials
    • Events
  • S2S notifications
    • Server-to-server notifications ?
    • App Store
    • Play Store
    • Huawei App Gallery
    • Amazon App Store
  • Integrations
    • Airship
    • Amplitude
    • Braze
    • Firebase
  • Advanced Features
    • Anonymous user
    • Associating content
    • Customising UI
      • Errors & alerts
      • Controllers (iOS) / Fragments (Android)
    • Deeplinks automations
    • Displaying users subscriptions
    • UI Analytics
    • Localization
    • Non-subscription products
    • Promoting your products
      • Self-promotion
      • Promoting In-App Purchases
    • Purchase interceptor
    • Purchase manually
    • Subscription status
    • Paywall Guidelines
  • Others
    • Frequently Asked Questions
    • Migration guides
      • Migrate to Purchasely
      • SDK
        • v2.1.3
        • v2.2.0
      • Webhooks
        • v3.0
  • TESTING
    • Testing Cycle Durations
Powered by GitBook

© Purchasely 2020-2023

On this page
  • Request
  • Sample header
  • Authenticating request and verifying signature (recommended)
  • Body
  • Model
  • Response

Was this helpful?

  1. Basic configuration
  2. Webhook

Receiving and understanding messages

Request

Sample header

Accept: application/json
X-PURCHASELY-SIGNATURE: ea909...ba5a6,
X-PURCHASELY-TIMESTAMP: 1580...929

Authenticating request and verifying signature (recommended)

To ensure that events are indeed coming from Purchasely Cloud Platform, you can authentify event using informations contained in the HEADER of the HTTP request :

  • X-PURCHASELY-SIGNATURE : message signature

  • X-PURCHASELY-TIMESTAMP : request timestamp to avoid replay attacks

This verification is optionnal.

The timestamp correspond to the query time and (UTC) and it can be ignored if the query is too old (more than 15 minutes ?)

The signature relies on a shared secret that you can find in your Purchasely Console (client_webhook_shared_secret) Purchasely Console > Applications > [YOUR APP] > Application settings

Sample code for signature verification (NodeJS) :

const crypto = require("crypto");

// Request headers
// ---------------
const xPurchaselyTimestamp = "1580909929";
const xPurchaselySignature = "ea909b88098b63ef93711cd14542403e5efe1a23c07d94a764bd4db55abba5a6";

// Signature verification
// ----------------------
const webhookSharedSecret = "foobar";
const dataToSign = webhookSharedSecret + xPurchaselyTimestamp;
const computedSignature = crypto
                          .createHmac("sha256", webhookSharedSecret)
                          .update(dataToSign)
                          .digest("hex");

if (computedSignature === xPurchaselySignature) {
  // request authenticated
}
require 'openssl'

# Request headers
# ---------------
x_purchasely_timestamp = '1580909929'
x_purchasely_signature = 'ea909b88098b63ef93711cd14542403e5efe1a23c07d94a764bd4db55abba5a6'

# Signature verification
# ----------------------
webhook_shared_secret = 'foobar'
data_to_sign = webhook_shared_secret + x_purchasely_timestamp
computed_signature = OpenSSL::HMAC.hexdigest('sha256', webhook_shared_secret, data_to_sign)

if (computed_signature == x_purchasely_signature) {
  # request authenticated
}
// Imports
// -------
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

// Request headers
// ---------------
val xPurchaselyTimestamp = "1580909929";
val xPurchaselySignature = "ea909b88098b63ef93711cd14542403e5efe1a23c07d94a764bd4db55abba5a6";

// Signature verification
// ----------------------
val webhookSharedSecret = "foobar"
val dataToSign = webhookSharedSecret + xPurchaselyTimestamp
val hmac = Mac.getInstance("HmacSHA256")
hmac.init(SecretKeySpec(webhookSharedSecret.toByteArray(), "HmacSHA256"))
val computedSignature = hmac.doFinal(dataToSign.toByteArray()).joinToString("") { "%02x".format(it) }

if (computedSignature == xPurchaselySignature) {
    // request authenticated
}

Body

Sample body

{
  "plan": "<plan vendorID defined in the Purchasely console>",
  "store": "APPLE_APP_STORE",
  "product": "<product vendorID define in the Purchasely console>",
  "user_id": "<user id you provided through the sdk>",
  "event_name": "SUBSCRIPTION_STARTED",
  "offer_type": "NONE",
  "api_version": 3,
  "environment": "SANDBOX",
  "purchased_at": "2021-11-07T17:41:17.000Z",
  "store_country": "FR",
  "next_renewal_at": "2021-11-07T17:44:17.000Z",
  "purchased_at_ms": 1636306877000,
  "event_created_at": "2021-11-07T17:41:34.188Z",
  "is_family_shared": false,
  "store_product_id": "<store product id defined in the store console>",
  "next_renewal_at_ms": 1636307057000,
  "event_created_at_ms": 1636306894188,
  "store_app_bundle_id": "<app bundle id defined in the store console>",
  "subscription_status": "AUTO_RENEWING",
  "store_transaction_id": "100000099999999",
  "original_purchased_at": "2021-11-07T17:41:18.000Z",
  "original_purchased_at_ms": 1636306878000,
  "effective_next_renewal_at": "2021-11-07T17:44:17.000Z",
  "purchasely_subscription_id": "subs_XFJFJEBFFU757FUJH",
  "effective_next_renewal_at_ms": 1636307057000,
  "store_original_transaction_id": "10000009999999"
}

Model

Event

Attributes

Attributes are meant to give you all the context needed to handle and deeply understand you subscriber lifecycle. Such as store, product, plan, purchased_at, is_family_shared...

Response

When called by Purchasely Cloud Platform, client backend should respond with a HTTP code :

  • HTTP 200 ⇒ the Event has been well received and processed (eg: the subscription has been activated)

  • Other than HTTP 200 or no response (timeout) ⇒ an error has occured and the Event could not be processed :

    • The user is warned through the SDK that something did not work

    • Purchasely Cloud Platform will retry several times to send the Event (max 25 times) in the following hours (except for HTTP 404).

This response from the client backend to the Purchasely Console is mandatory particularly for purchase events (e.g. new subscriptions) coming from the SDK, to ensure that the client backend has granted the user with the entitlements corresponding to the new purchase, and unlocked the access to the premium contents or features.

This response from the client backend is forwarded to the mobile SDK and an error message is displayed to the user, if it is different from HTTP 200.

PreviousWebhookNextManaging entitlements

Last updated 3 years ago

Was this helpful?

name : Event Name Possible values : ACTIVATE| DEACTIVATE | RENEWAL_DISABLED … () See to understand the exact meaning for each Event, when and why use them.

See the to understand the exact meaning for each Attribute.

full list
Events repository
full list