Skip to main content

Webhooks

Webhooks deliver real-time notifications when data changes in your Journeybee workspace. Use them to sync leads into your CRM, trigger a Zap, notify an ops channel, or drive any downstream workflow.
Webhooks today run through the connector subscription API (below). A more developer-oriented flow — including raw-signature HMAC, retries, and a UI for managing endpoints — is planned for a later release.

Quick start

Subscribe your endpoint to an event:
curl -X POST https://api.journeybee.io/v1/webhooks/subscriptions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_id": 42,
    "event": "leads.create",
    "url": "https://hooks.example.com/journeybee"
  }'
Response:
{
  "id": "42.leads.create.1713300000000",
  "integration_id": 42,
  "event": "leads.create",
  "url": "https://hooks.example.com/journeybee",
  "active": true,
  "message": "Webhook subscription created successfully"
}
Your endpoint will now receive a POST for every matching event.

Supported events

EventDescription
leads.createA lead was created
leads.updateA lead was updated
leads.deleteA lead was deleted
leads.notes_createA note was added to a lead
leads.notes_updateA lead note was updated
leads.notes_deleteA lead note was deleted
deals.createA deal was created
deals.updateA deal was updated
deals.deleteA deal was deleted
partners.createA partner was added
partners.updateA partner was updated
partners.contact_createA partner contact was created
partners.contact_updateA partner contact was updated
payments.processingA payout was initiated
payments.completedA payout completed
payments.failedA payout failed
mdf.payout_completedAn MDF claim payout completed
mdf.payout_failedAn MDF claim payout failed

Subscription API

Create a subscription

POST /v1/webhooks/subscriptions
Body:
FieldTypeRequiredDescription
integration_idintegeryesThe integration this subscription attaches to
eventstringyesOne of the supported events above
urlstringyesThe HTTPS endpoint to POST events to
descriptionstringnoFree-text note for your own records
The integration_id identifies which integration row the subscription hangs off. For Zapier-style self-serve subscriptions, use the public Journeybee connector integration ID. Ask support if you’re unsure which integration to use.

Delete a subscription

POST /v1/webhooks/subscriptions
Send DELETE with the hookUrl body field set to the subscription id returned at create time:
curl -X DELETE https://api.journeybee.io/v1/webhooks/subscriptions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "hookUrl": "42.leads.create.1713300000000" }'

Event delivery

Every subscribed event generates a single POST to your URL with:
  • Content-Type: application/json — the request body is a JSON payload described below.
  • Authorization: Bearer <token> — a JWT signed with your integration’s UUID as the secret. Verify this before processing the payload.

Example payload — leads.create

{
  "lead": {
    "uuid": "b1a9d5c3-...",
    "created_at": "2026-04-16T09:12:00.000Z",
    "updated_at": "2026-04-16T09:12:00.000Z",
    "status": "new",
    "source": "form",
    "company_name": "Acme Corp",
    "email": "buyer@acme.test",
    "phone_number": "+1-555-0100",
    "first_name": "Jane",
    "last_name": "Buyer",
    "partnership_name": "Northwind Referrals",
    "partnership_type": "referral",
    "created_by_user_uuid": "8e7d...",
    "created_by_user_email": "rep@northwind.test",
    "created_by_user_first_name": "Riley",
    "created_by_user_last_name": "Rep",
    "custom_fields": [
      {
        "uuid": "cf-...",
        "label": "Region",
        "type": "select",
        "options": [
          { "id": 1, "label": "EMEA" },
          { "id": 2, "label": "AMER" }
        ],
        "value": "EMEA",
        "custom_field_value_uuid": "cfv-..."
      }
    ],
    "tags": [{ "uuid": "tag-...", "label": "Hot" }],
    "assigned_users": [
      {
        "uuid": "u-...",
        "email": "ae@acme.test",
        "first_name": "Alex",
        "last_name": "AE"
      }
    ],
    "assigned_contacts": []
  },
  "configuration": []
}
Other events follow the same pattern — the entity key matches the resource (deal, partner, contact, etc.).

Verifying requests

The Authorization header contains a JWT signed with HS256 using your integration UUID as the shared secret. Decode and verify it to confirm the request is genuine.

Node.js (jsonwebtoken)

import jwt from "jsonwebtoken";

const INTEGRATION_UUID = process.env.JOURNEYBEE_INTEGRATION_UUID;

app.post("/webhook", (req, res) => {
  const header = req.headers.authorization ?? "";
  const token = header.startsWith("Bearer ") ? header.slice(7) : null;
  if (!token) return res.status(401).end();

  try {
    const claims = jwt.verify(token, INTEGRATION_UUID, {
      algorithms: ["HS256"],
    });
    // claims = { company_uuid, user_uuid, event_id, external_settings, api_key }
    processEvent(claims.event_id, req.body);
    res.status(200).end();
  } catch {
    res.status(401).end();
  }
});

Token claims

ClaimDescription
company_uuidThe Journeybee company the event belongs to
user_uuidThe user that triggered the event (falls back to an admin user)
event_idThe event name (e.g. lead_created, deal_updated)
api_keyOptional API key for callbacks into Journeybee
external_settingsYour stored integration settings, including authorisation[]
Always verify the JWT before acting on a payload. The integration UUID is the shared secret — do not commit it to source control and do not expose it in client-side code.

Delivery semantics

  • At-most-once: the worker sends one POST per event. There are no automatic retries on 5xx responses today, so your endpoint must return 2xx quickly and queue work asynchronously.
  • Timeouts: slow endpoints (>5s) may be dropped. Return a 2xx as soon as you’ve persisted the event, then process it out of band.
  • Ordering: events are not guaranteed to arrive in order. Use the updated_at field on the payload to reconcile.
  • Duplicates: duplicates are rare but possible. Key your idempotency off the entity uuid plus event_id.
Retries, signed timestamps, and a delivery log are on the roadmap (Platform phase 15). If you need guaranteed delivery today, poll the relevant list endpoints on an interval and reconcile against your local state.

Troubleshooting

  • Receiving 401s? Double-check that you’re verifying with the integration UUID (not your API key) and using HS256.
  • Not receiving events? Confirm the subscription exists by listing your current subscriptions:
    curl https://api.journeybee.io/v1/webhooks/subscriptions \
      -H "Authorization: Bearer YOUR_API_KEY"
    
  • Want to test delivery? Use a tool like webhook.site as the url and trigger an event (create a test lead, update a partner) from the app.