PlaneConnection uses webhooks in two directions:
- Inbound webhooks — receive events from third-party services (Stripe, Resend)
- Outbound webhooks — send events to your own endpoints when things happen in the platform
Inbound Webhooks
Inbound webhooks use signature verification instead of session tokens.
Stripe Webhooks
Endpoint: POST /api/webhooks/stripe
Receives Stripe payment events. Signature is verified using the stripe-signature header and a shared signing secret.
Events handled:
| Event | Action |
|---|
checkout.session.completed | Marks invoices as paid |
payment_intent.succeeded | Updates payment status |
customer.subscription.created | Syncs subscription status |
customer.subscription.updated | Syncs subscription changes |
customer.subscription.deleted | Marks subscription as cancelled |
invoice.paid | Updates subscription billing status |
invoice.payment_failed | Flags failed billing |
Stripe Connect Webhooks
Endpoint: POST /api/webhooks/stripe-connect
Receives events for Stripe Connect (multi-party payments, FBO onboarding, trip payment splits).
Resend Webhooks
Endpoint: POST /api/webhooks/resend
Receives email delivery events from Resend for deliverability monitoring and email analytics. Signature is verified using the webhook signing secret.
Events handled:
| Event | Description |
|---|
email.sent | Email accepted by Resend for delivery |
email.delivered | Email successfully delivered to inbox |
email.bounced | Email bounced (hard or soft) |
email.complained | Recipient marked email as spam |
email.clicked | Recipient clicked a link in the email |
email.opened | Recipient opened the email |
email.delivery_delayed | Email delivery is delayed |
email.suppressed | Email suppressed (previous bounce/complaint) |
Outbound Webhooks
You can configure outbound webhooks to receive notifications when events occur in your PlaneConnection workspace. Webhooks are managed via the API and require admin permissions.
Managing Webhooks
Base path: /api/v1/webhooks
| Method | Path | Description | Required Role |
|---|
GET | /webhooks | List webhooks | Admin/Manager |
GET | /webhooks/:id | Get a webhook with recent logs | Admin/Manager |
POST | /webhooks | Create a webhook | Admin |
PUT | /webhooks/:id | Update a webhook | Admin |
DELETE | /webhooks/:id | Delete a webhook and its logs | Admin |
POST | /webhooks/:id/test | Send a test event | Admin/Manager |
Create Webhook
curl -X POST "https://api.planeconnection.com/api/v1/webhooks" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Flight notifications",
"url": "https://your-app.example.com/webhooks/planeconnection",
"secret": "whsec_your_signing_secret",
"events": ["flight.scheduled", "flight.departed", "flight.arrived"],
"active": true,
"retry_count": 3,
"timeout_ms": 10000
}'
Webhook URLs targeting private/internal networks (RFC 1918, loopback, link-local, metadata
endpoints) are blocked to prevent SSRF attacks.
Webhook Configuration
| Field | Type | Required | Description |
|---|
name | string | Yes | Human-readable name (max 100 chars) |
url | string | Yes | HTTPS endpoint to receive events |
secret | string | No | Signing secret for HMAC-SHA256 verification |
events | string[] | Yes | Event types to subscribe to |
active | boolean | No | Enable/disable (default: true) |
headers | object | No | Custom headers to include in deliveries |
retry_count | integer | No | Max retry attempts, 0-10 (default: 3) |
timeout_ms | integer | No | Request timeout, 1000-30000ms (default: 10000) |
Signature Verification
When a secret is configured, each delivery includes an X-Webhook-Signature header containing an HMAC-SHA256 signature of the payload:
X-Webhook-Signature: sha256=a1b2c3d4e5f6...
Verify the signature in your handler:
const crypto = require("crypto");
function verifyWebhook(payload, signature, secret) {
const expected = crypto.createHmac("sha256", secret).update(payload).digest("hex");
return `sha256=${expected}` === signature;
}
Every webhook delivery includes these headers:
| Header | Description |
|---|
Content-Type | application/json |
X-Webhook-Event | Event type (e.g., flight.departed) |
X-Webhook-Timestamp | ISO 8601 delivery timestamp |
X-Webhook-ID | Webhook configuration ID |
X-Webhook-Signature | HMAC-SHA256 signature (if secret configured) |
Available Event Types
Query available event types at GET /api/v1/webhooks/events.
Reservations
| Event | Description |
|---|
reservation.created | New reservation created |
reservation.updated | Reservation details updated |
reservation.cancelled | Reservation cancelled |
reservation.checked_in | Guest checked in |
reservation.checked_out | Guest checked out |
Billing
| Event | Description |
|---|
invoice.created | Invoice generated |
invoice.paid | Invoice payment received |
invoice.overdue | Invoice past due date |
Flights
| Event | Description |
|---|
flight.scheduled | Flight scheduled |
flight.departed | Flight departed |
flight.arrived | Flight arrived |
flight.cancelled | Flight cancelled |
Maintenance
| Event | Description |
|---|
maintenance.due | Maintenance item becoming due |
maintenance.completed | Maintenance completed |
Customers
| Event | Description |
|---|
customer.created | New customer profile created |
customer.updated | Customer profile updated |
Delivery Logs
View webhook delivery history and troubleshoot failures.
Endpoint: GET /api/v1/webhooks/logs
| Parameter | Type | Description |
|---|
webhook_id | string | Filter by webhook ID |
event_type | string | Filter by event type |
status | string | Filter by status: pending, success, failed |
date_from | string | Start date filter |
date_to | string | End date filter |
limit | integer | Max results (default: 50, max: 100) |
offset | integer | Pagination offset |
Test a Webhook
Send a test event to verify your endpoint is receiving deliveries:
curl -X POST "https://api.planeconnection.com/api/v1/webhooks/wh_abc123/test" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event_type": "flight.scheduled",
"payload": {
"id": "flt_test",
"departure": "KJFK",
"arrival": "KLAX"
}
}'