BitelioBitelio

Sync unsubscribes to your database

Push every subscription change out of Bitelio and into your own user table with a workflow's webhook step

Whenever a contact's subscribed flag turns off — whether from a manual edit, the hosted unsubscribe page, a bounce, or a spam complaint — Bitelio emits contact.unsubscribed. A workflow listening for that event can relay it straight to your backend through a WEBHOOK step.

Setup

Build the receiving endpoint

Expose a public HTTPS route that checks a shared secret before touching the user record. Keep the handler fast — webhook deliveries are cut off after 10 seconds, so push anything slow onto a queue.

app.post('/bitelio/unsubscribes', async (req, res) => {
  if (req.header('authorization') !== `Bearer ${process.env.BITELIO_WEBHOOK_SECRET}`) {
    return res.status(401).end();
  }

  const { contact, event } = req.body;
  await db.user.update({
    where: { email: contact.email },
    data: {
      emailSubscribed: false,
      emailUnsubscribedReason: event.reason ?? 'user_action',
    },
  });

  res.status(204).end();
});

When the unsubscribe was automatic, event.reason carries "bounce" or "complaint"; for manual or self-service opt-outs the field simply isn't there.

Create the workflow

Under Workflows → New workflow:

  • Trigger: EVENT on contact.unsubscribed
  • Add a WEBHOOK step:
    • URL: https://api.example.com/bitelio/unsubscribes
    • Headers: { "Authorization": "Bearer your-shared-secret" }
    • Leave the body empty so Bitelio sends the default payload.

Turn the workflow on.

Mirroring resubscribes

For the opposite direction of the flag, clone the same structure into a second workflow triggered on contact.subscribed. Don't merge the two into one branched flow — a pair of small, single-purpose workflows is much simpler to keep an eye on.

The reverse direction

When the authoritative copy lives on your side — say a user flips their email preference inside your own settings page — push the change to Bitelio with PATCH /contacts/:id from your backend:

curl -X PATCH https://api.bitelio.com/contacts/cnt_abc \
  -H "Authorization: Bearer sk_your_secret_key" \
  -d '{"subscribed": false}'

Be aware this update emits contact.unsubscribed too, so the webhook you built above will echo the change right back to your handler. Since the write is idempotent the loop is normally harmless — just don't be surprised by it.

What's next