Webhooks
Webhook Integration Guide for Subscription Management
This guide is intended for developers looking to integrate real-time subscription event notifications into their applications. With our webhook system, you’ll receive automated POST requests to your designated URL for events like new sign-ups, renewals, and payment failures.
Getting Started
A webhook allows our system to send real-time updates 📡 to your application. We’ll POST a JSON payload to your specified endpoint whenever a relevant subscription event occurs.
Step 1: Create/Edit Subscription & Plug in Your Webhook URL
You can set up a webhook URL in the Flash web app either while creating a new subscription or by editing an existing subscription:
When creating a new subscription:
Head over to New Subs > Create a Subscription Plan
Make sure to click on the “Use Advanced Webhook Features” checkbox to make the Webhook Url field appear
Input your Webhook URL in the form when creating the subscription

After creating the Subscription, you will receive a url with the subscription and the subscription key. You can use this key to decode and verify the JWT token that comes with our event (see guide below).
When you have already created a subscription:
Head over to My Subscriptions
Select the subscription you want to add webhooks for
Click on “Edit Subscription”
Fill in/modify the Webhook Url field
The subscription key is also visible in this screen and can be used to decode and verify the JWT token that comes with our event (see guide below).

Step 2: Configure Your Webhook Endpoint
To receive webhook notifications, set up a POST endpoint in your application:
Ensure it accepts JSON payloads.
Process the data based on the event type and take appropriate actions.
Security Tip: Always use HTTPS to secure webhook transmissions.
Responding to Webhook Calls
Your webhook endpoint should respond with a 200 OK status to acknowledge receipt of the event. If no response or an error is received, we may retry the notification.
Event Types
The system triggers the following events, each sending a POST request with event data to your webhook:
Webhook Payload Structure
The data sent to your webhook URL will be structured as a JSON object containing two primary fields: eventType and data. The eventType field indicates the type of event, while the data field contains event-specific information.
Securing Webhooks with JWT
All webhooks include a JWT token in the Authorization header, allowing you to verify that the event is coming from Flash. You can decode and verify this token using the subscription key provided in the web app.
Example token:
{
"version": "1.0",
"eventType": {
"id": "1",
"name": "user_signed_up"
},
"user_public_key": "55a12716a6c4e8c95fc83dc046c3ea2209d3e3a1b87b15c48ef562b5a8599ed8",
"exp": "2024-05-01T08:48:38Z"
}Token Expiration: The token is valid for 1 hour.
To verify the token, decode it using your subscription key and the HS256 algorithm.
Handling Webhooks
Your webhook should always respond with a 200 OK status after processing the event. Failure to do so may cause the system to retry the notification.
Best Practices
Idempotency: Ensure that your webhook handler can process the same event more than once without causing errors or duplicate actions.
Logging: Implement logging for all webhook events to make troubleshooting easier.
FAQ
Can I set up multiple webhook URLs?
Conclusion
By integrating our webhook system, you can stay updated on key subscription events in real time, helping automate and optimize your processes. Feel free to contact our developer support team if you need any help.
Webhook Usage - full example
Assuming your webhook URL is https://webhook , you can refer to the following code:
const jwt = require('jsonwebtoken');
app.post('/webhook', (req, res) => {
const data = req.body; // Extract JSON data from the request
const authHeader = req.headers.authorization;
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
// Verify and decode the JWT token
const secret = 'your_secret_key';
jwt.verify(token, secret, (err, decodedToken) => {
if (err) {
return res.status(401).json({ error: 'Invalid token' });
}
const { version, eventType, user_public_key } = decodedToken;
// Process the data as needed
console.log('User public key:', user_public_key);
console.log('Event Type:', eventType);
});
// Access fields from the JSON payload
const userPublicKey = data.data.public_key;
const userName = data.data.name;
const userEmail = data.data.email;
// Process the data...
res.json({ ok: true });
});
from flask import request, jsonify
import jwt
@app.route('/webhook', methods=['POST'])
def webhook():
data = request.get_json()
auth_header = request.headers.get('Authorization')
token = auth_header.split(" ")[1] if auth_header else None
if not token:
return jsonify({'error': 'No token provided'}), 401
secret = 'your_secret_key'
try:
decoded_token = jwt.decode(token, secret, algorithms=['HS256'])
version = decoded_token.get('version')
event_type = decoded_token.get('eventType')
user_public_key = decoded_token.get('user_public_key')
print(f"User public key: {user_public_key}")
print(f"Event Type: {event_type}")
except jwt.ExpiredSignatureError:
return jsonify({'error': 'Token has expired'}), 401
except jwt.InvalidTokenError:
return jsonify({'error': 'Invalid token'}), 401
user_public_key = data.get('data').get('public_key')
user_name = data.get('data').get('name')
user_email = data.get('data').get('email')
return jsonify({'ok': True})
require 'json'
require 'jwt'
post '/webhook' do
data = JSON.parse(request.body.read)
auth_header = request.env['HTTP_AUTHORIZATION']
token = auth_header.split(' ')[1] if auth_header
halt 401, { error: 'No token provided' }.to_json unless token
secret = 'your_secret_key'
begin
decoded_token = JWT.decode(token, secret, true, algorithm: 'HS256')[0]
user_public_key = decoded_token['user_public_key']
event_type = decoded_token['eventType']
puts "User public key: #{user_public_key}"
puts "Event Type: #{event_type}"
rescue JWT::ExpiredSignature
halt 401, { error: 'Token has expired' }.to_json
rescue JWT::DecodeError
halt 401, { error: 'Invalid token' }.to_json
end
user_public_key = data['data']['public_key']
user_name = data['data']['name']
user_email = data['data']['email']
{ ok: true }.to_json
end
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import io.jsonwebtoken.*;
import java.util.Map;
@RestController
public class WebhookController {
@PostMapping("/webhook")
public ResponseEntity<?> handleWebhook(@RequestBody Map<String, Object> payload,
@RequestHeader("Authorization") String authHeader) {
String token = authHeader != null ? authHeader.split(" ")[1] : null;
if (token == null) {
return ResponseEntity.status(401).body(Map.of("error", "No token provided"));
}
String secret = "your_secret_key";
try {
Jws<Claims> decodedToken = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token);
String version = (String) decodedToken.getBody().get("version");
Map<String, Object> eventType = (Map<String, Object>) decodedToken.getBody().get("eventType");
String userPublicKey = (String) decodedToken.getBody().get("user_public_key");
System.out.println("User public key: " + userPublicKey);
System.out.println("Event Type: " + eventType);
} catch (ExpiredJwtException e) {
return ResponseEntity.status(401).body(Map.of("error", "Token has expired"));
} catch (JwtException e) {
return ResponseEntity.status(401).body(Map.of("error", "Invalid token"));
}
Map<String, Object> data = (Map<String, Object>) payload.get("data");
String userPublicKey = (String) data.get("public_key");
String userName = (String) data.get("name");
String userEmail = (String) data.get("email");
return ResponseEntity.ok(Map.of("ok", true));
}
}
require 'vendor/autoload.php'; // Include JWT library (e.g., firebase/php-jwt)
use \Firebase\JWT\JWT;
$secret = 'your_secret_key';
$data = json_decode(file_get_contents('php://input'), true);
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? null;
if ($authHeader) {
$token = explode(' ', $authHeader)[1];
} else {
http_response_code(401);
echo json_encode(['error' => 'No token provided']);
exit;
}
try {
$decodedToken = JWT::decode($token, $secret, ['HS256']);
$decodedArray = (array) $decodedToken;
$userPublicKey = $decodedArray['user_public_key'];
$eventType = $decodedArray['eventType'];
echo "User public key: $userPublicKey\n";
echo "Event Type: $eventType\n";
} catch (Exception $e) {
http_response_code(401);
echo json_encode(['error' => 'Invalid token']);
exit;
}
$userPublicKey = $data['data']['public_key'] ?? null;
$userName = $data['data']['name'] ?? null;
$userEmail = $data['data']['email'] ?? null;
echo json_encode(['ok' => true]);
Last updated
