Skip to main content
POST
Send everything your CRM knows about a contact or company to a single Ringee endpoint. Ringee upserts the record, links it to your externalId, and makes it callable. Pick the event you are sending in the request body above — each one has its own data shape.

The envelope

Every request uses the same four top-level fields:

Reading the response

The endpoint returns 202 Accepted for any authenticated request with a complete envelope. The real result is in the JSON body.
A 202 status code only means the transport was accepted. Do not treat it as a successful sync without checking status in the body.

Warnings

A processed response can also carry a warnings array. The event applied, but something you sent had no effect:
Warnings are how you find the bugs that do not fail: a misspelled field name, a number without a country code, an owner nobody in Ringee matches. Log them while you build and surface them on your settings screen — a field Ringee dropped silently is the most expensive kind of sync bug to find later.

What the endpoint guarantees

Ringee validates the whole payload — field shapes, the phone number, the campaign you named — before it writes anything. A failed response means nothing was created or updated, so you can correct the payload and send it again knowing Ringee holds no half-synced record.
Problems are reported together, not one per round trip. A missing externalId and a missing phoneNumber come back in the same message:
eventId is the idempotency key, scoped to your integration. A transport retry is free: the second delivery returns skipped and changes nothing. That also means a corrected payload needs a new id — the old one is already recorded.
Ringee patches, it does not replace. Send only what changed: null, undefined and empty strings leave the stored value alone. To blank a field, clear it in Ringee.

Event examples

Create or update a contact from your CRM’s current state.
string
required
Stable contact id in your system. The primary deduplication key.
string
required
Dialable number. Required because the point of a synced contact is that somebody can call it — see Phone numbers.
string
Display name.
string
Given name.
string
Family name.
string
Pre-composed full name.
string
Primary email.
string
External company id to link. Ringee creates the company when no link exists yet and companyName is present.
string
Fallback company name when a linked company is unavailable.
string
Contact position or title.
string (UUID)
Ringee campaign to add this contact to as a lead — see Adding a contact to a campaign.
string
Resolves a Ringee member in an organization workspace. An email nobody matches leaves the contact unassigned and returns a warning.
string
Accepted and kept in the stored snapshot, but not currently used for owner resolution.
string
Lead source label.
object
Arbitrary contact fields.
object
Provider-specific metadata.
Deduplication order: externalId first, then the normalized phoneNumber within the same workspace.
In a personal workspace the integration owner owns every synced contact, and ownerEmail is not used.

Phone numbers

Ringee normalizes data.phoneNumber to E.164 against real numbering plans. That normalized value is what agents dial and what deduplication matches on. A number with no leading + is read with United States as the assumed country, and the response tells you so. That assumption is wrong for most of the world, so send E.164.
Deduplication matches on the normalized number, so a contact stored under a differently normalized value will not match and a second contact is created. Your externalId link is immune to this: it resolves the same contact regardless of phone formatting.

Adding a contact to a campaign

Include data.campaignId on contact.upserted and the contact joins that outbound campaign as a lead, in the same request that syncs it.
The campaign id is the last segment of the campaign URL in the dashboard, under Campaigns. What it does:
  • The contact is added as a pending lead. If the campaign is already running, the lead is queued for dialing immediately.
  • A contact that is already a lead of that campaign is left untouched. Its attempts, status and disposition history survive every re-sync, so a CRM that replays contact.upserted on each edit never resets a lead’s progress.
  • Membership is only ever added. Dropping campaignId from a later event does not remove the lead — remove it in Ringee.
Campaigns exist only in organization workspaces, and the campaign must belong to the same workspace as your integration. A campaignId that is not a UUID, matches no campaign, or belongs to another workspace fails the event — and because validation runs before any write, the contact is not synced either. Correct it and resend with a new eventId.

Sending events well

Sync only when a field Ringee cares about actually changes: name, phone, email, company, job title, owner. Sending an event on every UI update wastes quota and makes your logs unreadable.
+14155550123 always wins over (415) 555-0123. See Phone numbers for what Ringee does with the difference.
An ignored field and an unmatched owner are invisible in production and obvious in the response. Fail your integration tests on any unexpected warnings entry.
If your CRM record was created or updated by a Ringee webhook, do not send it back. Store a sync_origin marker on those rows and skip them. See Build an integration.
Write the event to a local outbox table first, then attempt delivery. A contact save in your CRM should never fail because Ringee is momentarily unreachable.

Next steps

Click-to-call

Open a secure dialer for a synced contact

Outbound webhooks

Receive call activity back in your CRM

Logs and errors

Every inbound error message and how to fix it

Build an integration

The full two-way sync, end to end

Authorizations

X-Ringee-Api-Key
string
header
required

The cik_live_ secret key of a Custom Integration. Shown once at creation. Server-side only.

Body

application/json

Create or update a contact from your CRM's current state.

event
string
required

The event type.

Allowed value: "contact.upserted"
eventId
string
required

Unique, stable id for this event. Ringee deduplicates on it.

Example:

"crm_01HX5Z7K8MZP1Q4V0G9YJ2RH3T"

occurredAt
string<date-time>
required

When the change happened in your system.

Example:

"2026-05-23T14:30:00.000Z"

data
object
required

Omit a field to leave it untouched. Sending null, undefined or an empty string does not overwrite an existing value. The whole payload is validated before anything is written, so a rejected event leaves no partial contact behind.

Response

Accepted. Check status in the body to know whether the event was applied.

status
enum<string>
required

processed — applied. skipped — duplicate eventId, already applied earlier; treat as success. failed — accepted but could not be applied; fix and resend with a new eventId.

Available options:
processed,
skipped,
failed
eventId
string
required

Echoes the eventId you sent.

message
string

Present on skipped and failed. On failed it lists every problem found, separated by ; , so one request is enough to learn what to fix.

warnings
string[]

Non-fatal remarks about a payload that was applied anyway: an unknown or mistyped field that was ignored, a phone number read with an assumed country, an ownerEmail matching nobody in the workspace. Absent when there is nothing to report.