Platform can send webhooks to any publicly accessible server. When an event in Platform triggers a webhook (e.g., subscription is renewed), Platform will attempt to send this notification to the endpoint(s) you specify. You can specify up to 10 endpoints through the application. All notifications will be sent to all configured endpoints for your site.

When to use webhooks (Sample use case)

Suppose you are recording subscription expiration date on your end. When you receive subscription renewed notification, before making any changes to database, please send a request to get_subscription API to validate this notification.

Endpoint requirements (Responding to a webhook)

  • Your endpoint must be reachable at ports 80 (HTTP) or 443 (HTTPS)
  • Your endpoint must respond within 5 seconds
  • Your endpoint must respond with a 2XX status code (e.g., 200, 201, 204, etc).

Best Practices

Webhooks are not actionable on their own and should not be used for critical functions like issue App license. When a webhook notification is received, please send an API query to validate this notification.
If you are implementing webhooks. Test before go live. You have the ability to send test notifications to your endpoint(s) in Webhook tab.

2368

Configuration & Security

Webhooks will come from any of the following IP addresses:

  • 18.216.224.160

Solely rely on verifying the incoming request's IP address is not enough and insecure, please read the following docs(sample code) on how to verify a JWT token.

The following code demonstrates how Platform sends requests to webhook endpoints. NOTICE, please verify the $jwtToken which is signed by your App Secret.

$response = $client->request(
    'POST',
    $url,
    [
      'body' => json_encode($data),
      'headers' => [
      'Authorization' => 'Bearer ' . $jwtToken,
      'Content-Type' => 'application/json'
      ],
      'connect_timeout' => 5,
      'read_timeout' => 5,
    ]
);

Sample code on how to verify the authenticity of an incoming webhook:

function getToken (req) {
    if (req.headers.authorization && 
        req.headers.authorization.split(' ')[0] === 'Bearer') 
    { 
      // Authorization: Bearer i.am.jwttoken_that_needs_to_be_verified
      // Handle token presented as a Bearer token in the Authorization header
      return req.headers.authorization.split(' ')[1];
    } 
    // If we return null, we couldn't find a token.
    return null; 
  }
}

var jwt = require('jsonwebtoken');
token = getToken(req);
var decoded = jwt.verify(token, '<app secret>');
console.log(decoded);
// if no Exception is thrown, we can trust the request.
<?php
// the following code is associated with Laravel framework
include "vendor/autoload.php";
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;

$signer = new Sha256();
$tokenStr = $request->bearerToken();
$token = (new Parser())->parse($tokenStr);
var_dump($token->verify($signer, 'app secret'));

Webhook Details

The timestamp for webhooks is in UTC.

Automatic retries

If Platform receives an error in response to a webhook sent to your webhook URL, the notification will be retried. After ten failed attempts, Platform will stop trying. The interval between retries is approximately 5 + 2^x minutes, where x is the current attempt number.

Notification Types

There is no isTest property is real notifications.

{
  "isTest": true,
  "type": "canceled_subscription_notification",
  "subscription_id": 1,
  "user_id": 2,
  "app_id": 2,
  "status": "canceled",
  "created_at": 1540247277
}

{
  "isTest": true,
  "type": "expired_subscription_notification",
  "subscription_id": 1,
  "user_id": 2,
  "app_id": 2,
  "status": "expired",
  "created_at": 1540247279
}

{
  "isTest": true,
  "type": "renewed_subscription_notification",
  "subscription_id": 1,
  "user_id": 2,
  "app_id": 2,
  "status": "renewed",
  "created_at": 1540247280
}

{
  "isTest": true,
  "type": "successful_payment_notification",
  "subscription_id": 1,
  "user_id": 2,
  "app_id": 2,
  "status": "success",
  "created_at": 1540247281
}

{
  "isTest": true,
  "type": "failed_payment_notification",
  "subscription_id": 1,
  "user_id": 2,
  "app_id": 2,
  "status": "failed",
  "created_at": 1540247282
}