POST https://ingest.zelto.ai/webhooks/calls. A text
conversation is just a call with a transcript and no audio. Once it lands, it
runs through the full pipeline — transcription is skipped (there’s already a
transcript), and everything downstream (summaries, findings,
reviews, scorecards) works exactly as it does for voice.
The mechanics — minting a key, idempotency, error handling — are shared with
Custom & other providers. This page covers
what’s specific to text.
Mint a key
Text upload uses the same API key as every other custom upload. Follow Custom & other providers → Mint a key to create one under Settings → Integrations → API Call Upload, then expose it asZELTO_API_KEY.
Upload a chat conversation
Send the messages astranscript.turns — role: "user" for the person,
role: "assistant" for your agent — and leave the audio and telephony fields
out. Only call.externalId plus an agent reference are required.
chat.json
200 with { "received": true }.
Send:
agent.externalId(Zelto finds or creates the agent) oragentId(an existing agent’s UUID). Use a stable id per agent, not per conversation.call.externalId— a stable, unique id for the conversation (the dedup key).transcript.turns[]— the messages, in order, asuser/assistantturns.call.startedAt/call.endedAt— the conversation’s start and end timestamps (ISO 8601). Optional, but they let you sort and window by time.metadata.channel— record the channel (web-chat,sms,whatsapp,in-app) so you can filter on it later. There’s no dedicated channel field.
recordingUrlandrecordingUploadId— there’s no audio to re-host.- Per-turn
startSeconds/endSecondsandwords[]— those are for word-synchronized audio playback. durationSecondsandcustomer.number— voice/telephony fields with no text equivalent.
A delivery with neither a transcript nor a recording is treated as an
empty dial: Zelto acks it with
200 but creates no conversation, since
there’s nothing to analyze. A text conversation must carry at least one
transcript.turns entry.Tool calls
If your chatbot invokes tools mid-conversation (check availability, look up an order), forward each as atool turn carrying a structured toolCall — the
same shape voice agents use. Zelto shows it inline in the transcript and feeds
it into analysis. See
Tool calls for the field
reference and an example.
Idempotent re-uploads
call.externalId is the dedup key. Re-POSTing the same id updates the
conversation in place and never double-charges, so retries and later enrichment
re-sends are both safe. See
Idempotent re-uploads.
Conversations display as “calls”
Text conversations ingest and analyze fully, but Zelto’s model and UI are voice-first: an ingested conversation is labeled a “call” throughout, and its name defaults toCall <externalId> unless you give the agent a friendlier
name. There’s no first-class channel or modality field yet — the channel you
put in metadata is stored and queryable, but the interface won’t badge the
conversation as chat. Everything analytical still works; only the labeling is
voice-flavored.
Related
- Custom & other providers — the shared upload contract: keys, errors, and native Vapi/Retell payloads.
- Conversations — where uploaded conversations land.
- API reference — REST conventions and the full request shape, with a playground to test a payload.
- MCP — the same API key gives connected editors read/write access.

