Webhooks
Webhooks and Typescript
GraphQL
- Introduction
- Authentication
- Schema
- Customers
- Companies
- Tenants
- Threads
- Tiers
- Events
- Labels
- Messaging
- Pagination
- Error handling
- Error codes
- API Explorer
- Typescript SDK
Reference
- Customer cards
- Webhooks
- Overview
- Webhook Versions
- Using Typescript
- Thread created
- Thread status transitioned
- Thread assignment transitioned
- Thread labels changed
- Thread priority changed
- Note created
- Email received
- Email sent
- Slack message received
- Slack message sent
- Chat sent
- Chat received
- Thread Field created
- Thread Field updated
- Thread Field deleted
- Thread SLA status transitioned
- Customer created
- Customer updated
- Customer deleted
- Customer Group Membership Changed Event
- Request signing
- mTLS
- UI Components
- Attachments
Webhooks
Webhooks and Typescript
Our TypeScript SDK provide utilities to verify the webhook signature and parse the webhook body into a typed object.
import express from 'express';
import {
PlainWebhookSignatureVerificationError,
PlainWebhookVersionMismatchError,
verifyPlainWebhook,
} from '@team-plain/typescript-sdk';
// Plain HMAC Secret. You can find this in Plain's settings.
const PLAIN_SIGNATURE_SECRET = process.env.PLAIN_SIGNATURE_SECRET;
if (!PLAIN_SIGNATURE_SECRET) {
throw new Error('PLAIN_SIGNATURE_SECRET environment variable is required');
}
const app = express();
app.use(express.text());
app.post('/handler', function (req: Express.Request, res: Express.Response) {
// Please note that you must pass the raw request body, exactly as received from Plain,
const payload = req.body;
// Plain's computed signature for the request.
const signature = req.get('Plain-Request-Signature');
const webhookResult = verifyPlainWebhook(payload, signature, secret);
if (webhookResult.error instanceof PlainWebhookSignatureVerificationError) {
res.status(401).send('Failed to verify the webhook signature');
return;
}
if (webhookResult.error instanceof PlainWebhookVersionMismatchError) {
// The SDK is not compatible with the received webhook version.
// This can happen if you upgrade the SDK but not the webhook target, or vice versa.
// We recommend setting up alerts to notify you when this happens.
// Consult https://plain.com/docs/api-reference/webhooks/versions for more information.
console.error('Webhook version mismatch:', webhookResult.error.message);
// Respond with a non-2XX status code to trigger a retry from Plain.
res.status(400).send('Webhook version mismatch');
return;
}
if (webhookResult.error) {
// Unexpected error. Most likely due to an error in Plain's webhook server or a bug in the SDK.
// Treat this as a 500 response from Plain.
console.error('Unexpected error:', webhookResult.error.message);
res.status(500).send('Unexpected error');
return;
}
// webhookResult.data is now a typed object.
const webhookBody = webhookResult.data;
// You can use the eventType to filter down to a specific event type
if (webhookBody.payload.eventType === 'thread.thread_created') {
console.log(`Thread created: ${webhookBody.payload.thread.id}`);
}
// Respond with a 200 status code.
res.status(200).send('Webhook received');
});
We strongly recommend verifying the webhook signature before processing the webhook body. This ensures that the webhook was sent by Plain and not a malicious third party. However, if you want to skip the verification, you can use the parsePlainWebhook
function instead.
Was this page helpful?