Webhooks
Webhook API
You can use the Webhook API to see or edit the webhooks your application has created.
import { PatreonCreatorClient, WebhookClient } from 'patreon-api.ts'
// Replace with your client
declare const patreon: PatreonCreatorClient
const client = new WebhookClient(patreon.oauth)
// or:
const { webhooks } = patreon
Fetch webhooks
import { QueryBuilder, WebhookClient } from 'patreon-api.ts'
declare const client: WebhookClient
const query = QueryBuilder.webhooks.setAttributes({
webhook: ['paused', 'triggers', 'uri'],
})
const response = await client.fetchWebhooks(query)
for (const webhook of response.data) {
console.log(webhook.id, webhook.attributes.uri)
}
Create a webhook
You can create a new webhook for a certain campaign and specify the triggers and where to post to.
import { PatreonWebhookTrigger, WebhookClient } from 'patreon-api.ts'
declare const client: WebhookClient
const createdWebhook = await client.createWebhook({
campaignId: 'my-campaign-id',
triggers: [
PatreonWebhookTrigger.PostPublished,
],
uri: 'https://my-server-url.com/incoming-webhooks/patreon',
})
Edit a webhook
You can edit the triggers and uri of the webhook you specified while creating the webhook.
import { WebhookClient } from 'patreon-api.ts'
declare const client: WebhookClient
const updatedWebhook = await client.editWebhook({
id: 'my-webhook-id',
uri: 'https://new-website.com/incoming-webhooks/patreon'
})
If a webhook has failed to send events due to an outage or incorrect deploy, it will be paused. To unpause the webhook later, set paused
to false:
import { WebhookClient } from 'patreon-api.ts'
declare const client: WebhookClient
const updatedWebhook = await client.editWebhook({
id: 'my-webhook-id',
paused: false,
})
// or:
await client.unpauseWebhook('my-webhook-id')
Delete a webhook
WARNING
This will be unstable until the Patreon documentation has added this method. See this issue for more details.
import { WebhookClient } from 'patreon-api.ts'
declare const client: WebhookClient
await client.deleteWebhook('my-webhook-id')
Webhook server
Both methods for verifying requests will work with the following request libraries:
- Node.js v18+ (Undici) or request / response classes with the same methods
- HTTP server with
IncomingRequest
(and{ body: any }
being the JSON parsed request body) or a library that is built on this module.
Verify requests
To create a server for reading webhook payloads it is recommended to verify the incoming request from Patreon.
import { verify, type WebhookPayload } from 'patreon-api.ts'
async function handleRequest (request: Request, env: { WEBHOOK_SECRET: string }) {
const signature = request.headers.get('X-Patreon-Signature')
const body = await request.text()
if (!verify(env.WEBHOOK_SECRET, signature, body)) {
return new Response('Invalid request', { status: 400 })
}
const payload: WebhookPayload = JSON.parse(body)
// ...
}
You can get the webhook secret from the developer portal for your own webhooks or use <webhook>.attributes.secret
for webhooks created by your application.
Parse and verify
The library also exposes an parseWebhookRequest
utility to verify and parse the trigger:
import { parseWebhookRequest } from 'patreon-api.ts'
async function handleRequest (request: Request, env: { WEBHOOK_SECRET: string }) {
const parsed = await parseWebhookRequest(request, env.WEBHOOK_SECRET)
if (!parsed.verified) {
return new Response('Invalid request', { status: 400 })
}
const { event, payload } = parsed
console.log('new event: ' + event)
// ...
}
If your webhook only has one (type) of event you can also pass that event as a generic parameter:
import {
parseWebhookRequest,
PatreonWebhookTrigger,
type PatreonWebhookPostTrigger,
} from 'patreon-api.ts'
declare const request: Request
declare const env: {
WEBHOOK_SECRET: string
}
// payload and trigger will now be typed as post published events
const publishedPostResult = await parseWebhookRequest<PatreonWebhookTrigger.PostPublished>(request, env.WEBHOOK_SECRET)
// Or for any post event:
const anyPostResult = await parseWebhookRequest<PatreonWebhookPostTrigger>(request, env.WEBHOOK_SECRET)
Payload client
To quickly access common attributes, such as the campaign or user that triggered the webhook, you can use the payload client:
import { parseWebhookRequest, WebhookPayloadClient } from 'patreon-api.ts'
declare const env: {
PATREON_WEBHOOK_SECRET: string
}
async function handleRequest (request: Request) {
const result = await parseWebhookRequest(request, env.PATREON_WEBHOOK_SECRET)
if (result.verified) {
const payload = new WebhookPayloadClient(result.event, result.payload)
console.log(
'Campaign id: ' + payload.campaignId,
'User id: ' + payload.userId,
)
}
}
Convert payload
One usecase for a webhook server is to forward the event to another platform(s) using webhooks. Since all platforms have a different webhook body you must convert the JSON:API payload from Patreon into a different JSON object. To help with this conversion, you can use the payload client:
import { parseWebhookRequest, WebhookPayloadClient } from 'patreon-api.ts'
declare const env: {
PATREON_WEBHOOK_SECRET: string
DISCORD_WEBHOOK_URL: string
}
const converter = WebhookPayloadClient.convert({
posts: {
'posts:publish': {
title: '{{title}} is published',
color: 0,
fields: [{
name: 'Is public',
value: '{{is_public}}',
inline: true,
}],
},
}
})
async function handleRequest (request: Request) {
const result = await parseWebhookRequest(request, env.PATREON_WEBHOOK_SECRET)
if (result.verified) {
await fetch(env.DISCORD_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
embeds: [
converter(result.event, result.payload)
],
})
})
}
}