/compat/* for new integrations, and Charles-style legacy paths that match the original URL structure exactly. Both families normalize payloads to the same internal contracts and enqueue the same outbox jobs.
This layer is a controlled migration boundary, not the permanent architecture. Compatibility endpoints are rate-limited to 100 requests per minute per IP address.
Contact upsert
POST /compat/contact
Upsert a contact record using the Charles-compatible contact update shape. Switchbord syncs the contact to the backing store and returns an operation summary.E.164 phone number for the contact. Must be at least one character.
Your system’s identifier for this contact. Used to correlate records across systems.
The origin or intent of this update. Defaults to
"internal". Pass "opt_out" to set the contact’s subscriber status to blocked; any other value sets it to subscribed.Arbitrary key-value attributes. Switchbord reads
name, email, and locale from this object and maps them to first-class contact fields. All other keys are preserved.true when the contact was successfully synced.Always
"compatibility" for this endpoint."created" or "updated" depending on whether this is a new or existing contact.The synced contact record with its assigned ID and normalized fields.
A UUID for tracing this request in logs and audit entries.
| Status | Condition |
|---|---|
200 | Contact synced successfully |
400 | Validation failure — phone_number missing or malformed |
429 | Rate limit exceeded (100 req/min per IP) |
PUT /api/v1beta/contact/
Legacy Charles-compatible path with identical behavior toPOST /compat/contact. The response shape matches the original Charles API for drop-in compatibility.
Journey trigger
POST /compat/journey-trigger/
Trigger a journey using the compat-mode trigger contract. ThelegacyPath captures any path segments after the prefix and is used as the deduplication key for the outbox job.
One or more path segments that identify the journey. These are captured as a wildcard and used to route and deduplicate the trigger job.
E.164 phone number for the contact to enroll in the journey.
Optional flow identifier. Used in deduplication keys when provided.
Optional trigger identifier. Takes precedence over
flow_id in deduplication keys.Arbitrary key-value personalization data forwarded into the queued job payload.
POST /webhooks/v0/rest-trigger/organization//flow//trigger/
Legacy Charles-compatible journey trigger. TheorganizationId and flowId path parameters are captured and forwarded into the routed job payload.
Your organization identifier. Captured and forwarded in the job payload.
The flow to trigger. Captured and forwarded in the job payload.
POST /webhooks/v0/rest-trigger/organization//flow//trigger//
Identical to the path above but includes an explicittriggerId parameter. Use this when your Charles-era automation passes a trigger identifier.
An explicit trigger identifier. Used in the deduplication key for the outbox job.
Emarsys custom events
POST /api/v0/webhooks/incoming/emarsys/custom_external_event
Ingest a custom external event from Emarsys. Switchbord normalizes both the flattened and nested Emarsys contact payload styles, syncs the contact if a phone number or external reference ID is present, records a webhook event, and enqueues anintegration.emarsys.custom_event outbox job.
Authentication
WhenEMARSYS_WEBHOOK_SECRET is set in your environment, Switchbord validates the secret query parameter against it. Requests with a missing or incorrect secret receive a 401 response.
The shared secret value. Required when
EMARSYS_WEBHOOK_SECRET is configured.Request body — flat style
The name of the event. Must not contain whitespace.
E.164 phone number for the contact.
Your system’s identifier for the contact.
Email address for the contact.
Arbitrary key-value payload forwarded into the outbox job.
Optional voucher pool name, forwarded into the outbox job.
Request body — nested style
Switchbord also accepts nested contact payloads withcontact or contact_data objects:
| Status | Condition |
|---|---|
200 | Event accepted and queued |
400 | Validation failure — event_name missing or contains whitespace |
401 | Secret validation failed |
