# 🔔 Webhooks div h3 Real-Time Event Notifications p Webhooks allow you to receive real-time notifications when subscription events occur in your Appstle account. Build reactive, event-driven integrations with automatic retries, signature verification, and detailed delivery logs. div Webhooks are **HTTP POST requests** sent to a URL you configure (your endpoint). When an event happens, Appstle sends a POST request with event data to your endpoint. **Powered by [Svix](https://www.svix.com/)** — Enterprise-grade webhook infrastructure with: - ✅ Automatic retries with exponential backoff - ✅ Cryptographic signature verification - ✅ Detailed delivery logs and monitoring - ✅ Developer-friendly debugging tools ## 🚀 Getting Started div div ### 1️⃣ Configure Your Endpoint - Log in to your Appstle dashboard - Navigate to **Settings** → **Webhooks** - Add your webhook endpoint URL - Select which events you want to receive div ### 2️⃣ Respond Quickly - Return a `2xx` status code (e.g., `200 OK`) - Process events **asynchronously** in background - Return success immediately - Timeouts trigger automatic retries div ### 3️⃣ Verify Signatures - **Always** verify webhook signatures - Ensures requests are authentic - Prevents unauthorized access - See [Signature Verification](#signature-verification) below ## 📡 Event Types div Appstle sends webhooks for the following **subscription events**: | Event Type | Description | Payload Type | | --- | --- | --- | | `subscription.created` | New subscription created | Subscription Contract | | `subscription.updated` | Subscription details updated | Subscription Contract | | `subscription.activated` | Subscription activated | Subscription Contract | | `subscription.paused` | Subscription paused | Subscription Contract | | `subscription.cancelled` | Subscription cancelled | Subscription Contract | | `subscription.next-order-date-changed` | Next order date modified | Subscription Contract | | `subscription.billing-interval-changed` | Billing frequency changed | Subscription Contract | | `subscription.billing-success` | Payment processed successfully | Billing Attempt | | `subscription.billing-failure` | Payment failed | Billing Attempt | | `subscription.billing-skipped` | Billing cycle skipped | Billing Attempt | | `subscription.upcoming-order-notification` | Upcoming order reminder | Billing Attempt | ## Webhook Payload All webhooks follow this structure: ```json { "type": "subscription.created", "data": { // Event-specific payload } } ``` ### Subscription Contract Events Events like `subscription.created`, `subscription.updated`, `subscription.activated`, `subscription.paused`, `subscription.cancelled`, `subscription.next-order-date-changed`, and `subscription.billing-interval-changed` contain: ```json { "type": "subscription.created", "data": { "id": "gid://shopify/SubscriptionContract/12345", "status": "ACTIVE", "customer": { "id": 6789, "email": "customer@example.com", "firstName": "John", "lastName": "Doe" }, "billingPolicy": { "interval": "MONTH", "intervalCount": 1 }, "deliveryPolicy": { "interval": "MONTH", "intervalCount": 1 }, "lines": [...], // Additional contract details } } ``` ### Billing Attempt Events Events like `subscription.billing-success`, `subscription.billing-failure`, `subscription.billing-skipped`, and `subscription.upcoming-order-notification` contain: ```json { "type": "subscription.billing-success", "data": { "id": 98765, "contractId": "gid://shopify/SubscriptionContract/12345", "status": "SUCCESS", "billingDate": "2026-02-01", "order": { "id": "gid://shopify/Order/11111", "name": "#1234", "totalPrice": "49.99" }, "attemptCount": 1, // Additional billing details } } ``` ## Signature Verification **Every webhook request is signed** by Svix. You must verify the signature to ensure the request is authentic and hasn't been tampered with. Svix includes these headers in every webhook request: - `svix-id`: Unique message ID - `svix-timestamp`: Unix timestamp of when the message was sent - `svix-signature`: Cryptographic signature ### Verification Example (Node.js) ```javascript const { Webhook } = require('svix'); const secret = 'whsec_your_webhook_signing_secret'; app.post('/webhooks/appstle', (req, res) => { const payload = JSON.stringify(req.body); const headers = { 'svix-id': req.headers['svix-id'], 'svix-timestamp': req.headers['svix-timestamp'], 'svix-signature': req.headers['svix-signature'], }; const wh = new Webhook(secret); let event; try { event = wh.verify(payload, headers); } catch (err) { return res.status(400).send('Webhook signature verification failed'); } // Process the verified webhook console.log('Event type:', event.type); console.log('Event data:', event.data); res.status(200).send('OK'); }); ``` ### Verification Examples in Other Languages - [Python](https://docs.svix.com/receiving/verifying-payloads/how#python) - [Go](https://docs.svix.com/receiving/verifying-payloads/how#go) - [Ruby](https://docs.svix.com/receiving/verifying-payloads/how#ruby) - [PHP](https://docs.svix.com/receiving/verifying-payloads/how#php) - [Java](https://docs.svix.com/receiving/verifying-payloads/how#java) - [C#](https://docs.svix.com/receiving/verifying-payloads/how#c) Find your webhook signing secret in your Appstle dashboard under **Settings** → **Webhooks**. ## Testing Webhooks ### Using Svix Play Svix provides a testing tool to send sample webhooks to your endpoint: 1. Go to your Appstle dashboard → **Settings** → **Webhooks** 2. Click on your endpoint 3. Use the "Send Example" feature to send test events 4. Verify your endpoint receives and processes the webhook correctly ### Local Development Use tools like [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.me/) to expose your local development server and test webhooks: ```bash ngrok http 3000 ``` Then add your ngrok URL (e.g., `https://abc123.ngrok.io/webhooks/appstle`) as a webhook endpoint in your Appstle dashboard. ## Retry Schedule If your endpoint doesn't return a `2xx` status code, Svix automatically retries the webhook delivery: - **Retry Schedule:** Exponential backoff over 5 attempts across 3 days - **Manual Retry:** You can manually retry failed webhooks from the Svix dashboard - **Endpoint Disabling:** Endpoints are automatically disabled after sustained failures to prevent wasted resources View delivery attempts and retry history in your Appstle dashboard under **Settings** → **Webhooks** → **Message Logs**. ## Troubleshooting ### Common Issues | Issue | Solution | | --- | --- | | Signature verification fails | Ensure you're using the correct webhook signing secret from your dashboard. Don't modify the raw request body before verification. | | Timeouts | Return `200 OK` immediately and process events asynchronously. Avoid long-running operations in your webhook handler. | | Wrong status codes | Always return `2xx` for successful receipt (even if you encounter business logic errors). Use `4xx` only for malformed requests. | | CSRF protection blocking webhooks | Exempt your webhook endpoint from CSRF checks in your web framework. | | Duplicate events | Webhooks can be delivered more than once. Use the `svix-id` header to make your processing idempotent. | ### Debugging Tips - Check the **Message Logs** in your Appstle dashboard to see delivery attempts and responses - Log the raw webhook payload to understand the exact data structure - Verify your endpoint is publicly accessible (not behind VPN/firewall) - Test with a simple endpoint that just logs and returns `200 OK` ### Need Help? Contact support@appstle.com with your endpoint URL and example `svix-id` for assistance. *Last updated: January 2026*