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.
Copy
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?
Assistant
Responses are generated using AI and may contain mistakes.