Import and webhooks

Most of what your agents need to know comes from them: they log what they do. The rest arrives on its own: the CRM you're leaving, calls your voice agents make, meetings people book, forms they fill in, payments. Both are set up by a workspace admin in the app, under Settings → Import and Settings → Webhooks.

Everything that comes in goes through the same rules as an agent's writes: people are matched by email, phone or handle (never duplicated), opt-outs follow their identities, records count toward your plan, and each change lands in the audit log.

Import

How imports treat what's already there:

Webhooks

Each source gets its own URL, https://undocrm.com/in/<token>, to paste into the tool. The URL is the credential: it's shown once, and an admin can replace it at any time (the old one stops working). Each source keeps a log of its last deliveries and what became of them.

Source What's logged
Vapi Each call, from its end-of-call report: the summary, transcript and recording, and structured data as properties.
Retell Each call, from call_analyzed: the call summary, transcript and recording, and custom analysis data as properties.
Bland Each completed call, with its summary and transcript.
Cal.com, Calendly Bookings, reschedules and cancellations, on the attendee, with an open task for the meeting that moves or closes with the booking.
Typeform, Tally, Webflow forms Each submission, on the person who sent it. Answers to short questions become properties.
Stripe Customers, payments, refunds, failed payments (with a follow-up task) and subscriptions. A payment sets the lifecycle stage to customer.
Custom Anything that can POST JSON: Zapier, Make, n8n, or your own code.

A source can count as an agent's work. Attribute a Vapi source to your voice agent, and its calls show as that agent's, in timelines, briefs and the audit log; an outbound call to someone another agent has claimed is flagged, as it would be for any agent.

Deliveries are idempotent: when a provider sends the same event twice, it's logged once. Events a source doesn't log (a call still in progress, an unrelated Stripe event) are answered with 200 and skipped, with the reason in the source's log. A paused organization or a full record limit is answered with 402, so providers that retry deliver the event again after it's resolved.

Custom JSON

POST one object per event. person is any identity (email, phone, or linkedin:handle); leave out summary to save the contact without a conversation.

curl -X POST "https://undocrm.com/in/$TOKEN" -H "content-type: application/json" -d '{
  "person": "jane@acme.com",
  "name": "Jane Doe",
  "company": "Acme",
  "channel": "sms",
  "direction": "inbound",
  "summary": "Replied yes to the webinar invite.",
  "facts": { "webinar": "Nov 3" },
  "follow_ups": [{ "due": "2d", "action": "Send the webinar link" }],
  "external_id": "zap-123"
}'
Field
person, email, phone, identities Who it's about. At least one.
name, title, company, lifecyclestage Filled in when the person has none yet.
channel, direction, summary, content, occurred_at The conversation. direction is inbound, outbound or internal.
facts Properties, as an object or as [{ "key", "value" }].
follow_ups Tasks: [{ "due": "3d" or an ISO date, "action": "..." }].
external_id Your id for the event; the same id is never logged twice.