Webhooks
It's often the case you need to call from your app an external webhook or receive a webhook from an other products and take actions from it.
Trigger a Webhook
Say you built a complex AI flow using Stack AI or Wordware that takes a prompt and output something and you want to trigger the flow when a user clicks on a button in your app.
You could do a simple fetch(webhookurl) in your front-end, but doing that would expose your webhook URL and everyone would be able to trigger.
So you need to add an endpoint in your server to trigger the wehhook.
1. Define a new route in the server router
/app/core/trpc/server/yourRoute.tsx
import { z } from 'zod'
import { Trpc } from '@/core/trpc/base'
export const TriggerWebhookRouter = Trpc.createRouter({
wordware: Trpc.procedure
.input(z.object({ prompt: z.string() }))
.mutation(async ({ ctx, input }) => {
const response = await axios.post(
'https://.../', // your webhook URL
{
prompt: input?.prompt,
},
)
return response.data
}),
})
2. Export your newly created router
/app/core/trpc/server/index.tsx
Trpc.createRouter({
auth: AuthenticationRouter,
...
triggerWebhook: TriggerWebhookRouter
}),
3. Use it in the front-end
...
const { mutateAsync: triggerWebhook } =
Api.triggerWebhook.wordware.useMutation()
const generateOutput = async () => {
await triggerWebhook({ prompt: 'A awesome picture of marbles' })
}
return (
<>
<Button onClick={generateOutput}>Generate Output</Button>
</>
)
Receive a Webhook
Let's say you set-up a system on Zapier where everytime it processes a document, it needs to send you a request (with the document ID) so you can update your document to 'processed' status in your app.
Create a new file in /app/routes/api.webhook.document.tsx
.
Your webhook will be live at yourapp.com/api/webhook/document
. This will be the production URL to give Zapier.
import { Database } from '@/core/database'
import { headers } from 'next/headers'
import { NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest, res: NextResponse) {
try {
console.log('Webhook received')
const database = await Database.getUnprotected()
const body = await req.json()
// do something with the webhook body
await database.document.update({
where: {
id: body?.id,
},
data: {
status: 'processed',
},
})
return new NextResponse(`Webhook successful`, {
status: 200,
})
} catch (error: any) {
console.error('Could not handle webhook')
console.error(error)
return new NextResponse(`Unknown error: ${error.message}`, {
status: 500,
})
}
}
export const action: ActionFunction = async ({ request }) => {
try {
console.log('Webhook received')
const ctx = await AuthenticationServer.getHttpContext({ request })
const body = await request.json()
// do something with the webhook body
await ctx.databaseUnprotected.document.update({
where: {
id: body?.id,
},
data: {
status: 'processed',
},
})
return new Response(`Webhook successful`, {
status: 200,
})
} catch (error: any) {
console.error('Could not handle webhook')
console.error(error)
return new Response(`Unknown error: ${error.message}`, {
status: 500,
})
}
}
If you would like to test your webhook in the workspace, use the endpoint found on your project overview page as the base url for the callback.
If you're looking to receive a webhook to stripe, check out this guide.