Back to all integrations
Webhook

Inbound Webhooks

Receiving events from another system into AppBO and starting a workflow from the payload they carry.

On this page
What it connectsHow to connect itWhat data movesWorked exampleLimits and gotchas
Need this wired up?

Bring your stack to a call and we will connect it, test every field in both directions, and hand it over documented.

Book a call
01

What it connects

An inbound webhook is a URL the platform gives you, which an external system calls when something happens on its side. On the sending side is anything that can make an HTTP POST: your own application, a form host, a payment processor, a scheduling tool, an IoT device, a CI pipeline, an automation platform. On the receiving side is an AppBO workflow that starts the moment the request lands and can read the fields out of the request body.

The reason to use one instead of the API is direction and ownership. With the API, your code is responsible for deciding when to act and for knowing what the platform's current state is. With an inbound webhook, the external system simply announces facts as they happen, and the automation logic. Find or create the contact, branch on a value, send the message, move the opportunity. Lives inside the platform where a non-developer can read and change it. That division survives staff turnover far better than business rules buried in a worker process.

Inbound webhooks are the right tool when the event is genuinely event-shaped: a payment succeeded, a ticket was closed, a shipment left the warehouse, a lead filled in a form you host yourself. They are the wrong tool for bulk backfill, for anything that needs a synchronous answer in the response body, and for cases where you need to read a lot of platform state before deciding: those belong to the REST API.

02

How to connect it

  1. Create the workflow in AppBO that will consume the event, and set its trigger to the inbound webhook type. Give it a name that identifies the sending system, because the URL itself is opaque.
  2. Copy the webhook URL the trigger generates. Treat it as a secret: anyone holding it can start your workflow with a payload of their choosing.
  3. Capture a real sample payload before you build any logic. Either point the sending system at a request-inspection service first, or send one live event and let the trigger record it, so that the platform learns the payload's field structure from real data rather than from your assumptions.
  4. Confirm the sending system's content type. Send JSON with a Content-Type: application/json header; a form-encoded body or a mismatched header is the most common reason fields appear empty in the workflow.
  5. Keep the payload flat where you can. Deeply nested objects and arrays are harder to reference inside workflow steps than a one-level structure with explicit keys, so if you control the sender, flatten before posting.
  6. Include a stable identity key in every payload. An email address, a phone number in E.164, or an external identifier you also store on the contact. Without one the workflow cannot reliably decide whether to update or create.
  7. Include an event identifier and a timestamp from the sender. You will need both to de-duplicate retries and to discard out-of-order events.
  8. Add a shared secret you control. Since the trigger consumes whatever is posted, the practical pattern is a secret value in the payload (or a header the workflow can read) that the first workflow step checks, dropping anything that does not match.
  9. Map the payload fields onto the contact. Decide field by field whether the inbound value should overwrite, only fill when empty, or be ignored.
  10. Build the find-or-create step explicitly, keyed on your identity field, before any step that sends a message or moves an opportunity.
  11. Add a guard branch for malformed events: missing identity key, failed secret check, or a timestamp older than your tolerance. Route those to a no-op or a notification rather than letting them fall through into the happy path.
  12. Verify the connection is live by sending a test event and watching the workflow's execution history. Confirm it entered, confirm the field values resolved, confirm the contact was found or created as expected.
  13. Check what the sender saw. Confirm it received a success status; if it logged a timeout or an error it will retry, and you need to know that before you go live.
  14. Run the end-to-end test once more with a payload that should be rejected, and confirm it is.
  15. Document the URL, the expected payload shape and the owning team somewhere your colleagues will find it, then enable the sender in production.
03

What data moves

External system into the platform

  • The HTTP request body, whose fields become referenceable values inside the triggered workflow.
  • Identity fields used to resolve a contact: email, phone, or an external identifier stored on a custom field.
  • Business payload: amounts, status values, product or service names, dates, free-text notes.
  • Metadata you choose to send: event identifier, event type, sender timestamp, source system name.
  • Request headers, to the extent the trigger exposes them. Check what is available before relying on a header for authentication.

Platform back to the external system

  • An HTTP status code acknowledging receipt, and nothing more of substance.
  • No workflow results, no contact identifier, no branch outcome. The response is an acknowledgement, not an answer.

What does not move

  • Anything the sender did not put in the request. The platform cannot pull additional detail from the source system on its own. If the workflow needs more, it must call that system's API in a later step.
  • Synchronous results. If your sender needs to know what happened, the platform must call it back separately.
  • File attachments as part of the trigger payload. Send a URL the platform can fetch instead.
  • Guaranteed ordering. Two events sent milliseconds apart may be processed in either order.
  • Historical events from before the webhook existed. Backfill belongs to the REST API.
04

Worked example

Scenario: an externally hosted booking tool must create or update the contact in AppBO and start a reminder sequence whenever a session is booked.

  1. You create a workflow named Booking tool: session booked, set its trigger to inbound webhook, and copy the generated URL into your secret store.
  2. You configure the booking tool to POST on its session.booked event, with a JSON body containing event_id, event_type, occurred_at, email, phone, full_name, session_start, practitioner and a shared_secret field.
  3. You trigger one real booking so the trigger captures a live sample and learns the field names.
  4. A customer books a session. The booking tool POSTs the payload; the platform responds with a success status and the workflow enters.
  5. Step one compares shared_secret against the stored value. It matches, so execution continues; a mismatch would route to a terminate branch.
  6. Step two checks that email is present and that occurred_at is within the last hour. Both pass.
  7. Step three finds or creates the contact by email. No contact exists, so one is created with the name and phone from the payload, tagged booking-tool, with session_start and practitioner written to custom fields.
  8. Step four branches on practitioner to pick the right reminder template.
  9. Step five sends an immediate confirmation email, then waits until twenty-four hours before session_start and sends an SMS reminder.
  10. The booking tool retries the same event an hour later because its own log recorded a timeout. The workflow enters again; the guard step sees an event_id it has already recorded on the contact and terminates before the confirmation email is sent a second time.
  11. The customer reschedules. A second event arrives with a new event_id and a later session_start; the workflow finds the existing contact by email, updates the custom field, and the reminder recalculates against the new date.
05

Limits and gotchas

Rate limiting

An inbound webhook endpoint is not an unlimited ingest pipe, and workflow executions are a metered resource on the account. A sender that bursts thousands of events (a nightly batch job, a backfill, a runaway loop) can be throttled or can consume a surprising amount of the account's execution budget. Throttle on the sending side, and never use an inbound webhook as a bulk import mechanism.

Retries and idempotency

The platform does not de-duplicate for you. Most senders retry on timeout or on any non-2xx response, and many retry on a response that simply took too long even though it succeeded, so the same event will arrive twice. Always send an event identifier, record it on the contact or in a lookup, and check it in the first guard step. Without that, retries produce duplicate emails, duplicate opportunities and duplicate charges in whatever the workflow touches downstream.

Field mapping traps

The trigger learns the payload shape from samples, so a field that was absent from your sample will not be referenceable later. Always include optional keys with empty values rather than omitting them. Nested objects and arrays are awkward to address; flatten at the sender. Numbers arriving as strings, dates in an unexpected format, and phone numbers without a country code are all silent mapping failures that surface as empty fields or skipped branches rather than errors.

Duplicate contact creation

If the identity key is missing or inconsistent (email on some events, phone on others) a find-or-create step will create a second contact. Pick one key, require it, and reject events that lack it instead of letting the workflow improvise.

Sandbox versus live

Point your sender's test mode at a workflow in a test sub-account, never at the live one. A test payload hitting a live workflow with a real phone number sends a real message. Keep the test and production URLs in separate secret entries and label them unambiguously.

Authentication

The URL is the only thing standing between your workflow and the open internet, and it is not a signature. Add a shared secret in the payload and verify it in the first step. Rotate the webhook URL if it is ever committed to a repository, pasted into a ticket, or shared with a departing vendor, and remember that rotating it means reconfiguring every sender.

What commonly breaks

  • A sender changing its payload shape in a release, silently emptying the fields the workflow depends on.
  • Form-encoded bodies or a missing JSON content type.
  • Events arriving out of order, so an older status overwrites a newer one.
  • A workflow edited in place while live traffic is flowing through it.
  • The URL leaking and being replayed.
  • Senders treating a slow response as a failure and retrying indefinitely.

Connect it with us.

We wire the integration, map the fields, test both directions and hand it over with the SOPs your team needs to run it.

Book a call