Skip to main content

Connect anything

Integrations and webhooks with a backend behind them

Receive and verify webhooks, call other APIs and keep systems in sync, with storage, queues and cron in the same project.

No credit card · Data stored in the EU

What does an integration need?

Most integrations follow the same pattern. Something happens in one system, a webhook arrives (or a scheduled job notices the change), and your code updates another system. The hard parts are around the edges: checking the signature, storing the event so it isn't lost, retrying when the other side is down, and catching what slipped through.

Webhook gateways such as Svix and Hookdeck handle delivery, then hand the event to your backend. Codehooks is that backend. The endpoint, the database, the queue and the cron job that reconciles at night all live in one project.

Signature checks use webhook-verify, our open source package that covers more than 20 providers with one call.

Shopify orders into your CRM

The endpoint verifies and stores each order, then a worker sends it on. If the CRM is down, the order is still in the database with synced set to false.

index.js
import { app, Datastore } from 'codehooks-js';
import { verify } from 'webhook-verify';

// Shopify calls this endpoint, so it skips the API key check
app.auth('/webhook/*', (req, res, next) => next());

app.post('/webhook/shopify', async (req, res) => {
const secret = process.env.SHOPIFY_WEBHOOK_SECRET;
if (!verify('shopify', req.rawBody, req.headers, secret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const conn = await Datastore.open();
const saved = await conn.insertOne('orders', { order: req.body, synced: false });
await conn.enqueue('toCrm', { id: saved._id });
res.json({ ok: true }); // reply fast, do the work in the worker
});

app.worker('toCrm', async (req, res) => {
const conn = await Datastore.open();
const { order } = await conn.getOne('orders', req.body.payload.id);
await fetch(process.env.CRM_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: order.email, total: order.total_price }),
});
await conn.updateOne('orders', req.body.payload.id, { $set: { synced: true } });
res.end();
});

export default app.init();

Set SHOPIFY_WEBHOOK_SECRET and CRM_URL with coho set-env before you deploy.

Questions about integrations

Common questions about building with Codehooks.

Which webhook providers are supported?
Any service that sends an HTTP request can call a Codehooks endpoint. For signature verification, webhook-verify handles more than 20 providers, including Stripe, Shopify, GitHub, Slack, Discord and Twilio. The webhook examples have a complete handler for each of the common ones.
Can I send webhooks to my own customers?
Yes. The webhook delivery system template gives you outbound webhooks with signing, retries and delivery logs, running in your own project.
How do I keep two systems in sync?
Use webhooks for changes as they happen, and a scheduled job to catch anything that was missed. Records that failed to sync stay in the database with a flag, so the nightly job can queue them again. Integration sync walks through the whole pattern.
How is this different from Svix or Hookdeck?
Svix and Hookdeck are webhook gateways. They are good at ingesting, retrying and delivering events, but they hand each event to your backend. Codehooks is the backend, so you can store an event, query it later and run your own logic on it in the same project.

Building with a coding agent

Ask your agent to start from a webhook template with coho create --template, set the secrets with coho set-env, deploy, and check incoming events with coho log -f.

Connect your first service

Deploy a webhook handler from a template and point your provider at it.