Skip to main content

Customer API — Overview

The Customer API is how you push your own call data into Zipteams and get AI analysis back.

You send us a call recording plus a small amount of context (who the agent was, who the customer was). Zipteams transcribes the recording, runs its AI analysis, and — if you ask for it — posts the results back to a URL you control.

There are four things to understand, and they are documented one per page:

#SectionDirectionPurpose
1Call Sync APIYou → ZipteamsSend a call recording + context so Zipteams can analyse it
2Disposition Status Update APIYou → ZipteamsUpdate a customer's status / custom fields without sending a call
3Call Summary CallbackZipteams → YouPer-call AI analysis, posted back to your callback_url
4Customer Summary CallbackZipteams → YouContact-level rollup of AI analysis, posted back to your URL

Sections 1 and 2 are APIs you call. Sections 3 and 4 are webhooks we call.

Separately, and optional: the Chrome Extension can surface a contact's insights inside your own web interface. It needs no API key and is not part of the four sections above.


How the flow works​

 ┌──────────────┐   1. POST call data      ┌─────────────────────┐
│ Your system │ ───────────────────────► │ Zipteams API │
└──────────────┘ └──────────┬──────────┘
▲ │
│ │ 2. queued, one record at a time
│ ▼
│ ┌─────────────────────┐
│ │ Zipteams platform │
│ │ • fetch recording │
│ │ • transcribe │
│ │ • AI analysis │
│ └──────────┬──────────┘
│ │
│ 3. Call Summary Callback │
└─────────────────────────────────────────────┘
4. Customer Summary Callback
(on request)

The API responds immediately with 200 OK as soon as your payload is accepted. It does not wait for the recording to be downloaded, transcribed or analysed — that happens asynchronously and takes a few minutes depending on the length of the recording.

200 OK means "accepted", not "processed"

A 200 response only confirms that your request was well-formed and queued. A call can still fail to sync afterwards — for example if the recording URL is not reachable or the agent does not exist on Zipteams. See Why a call did not sync below.


Endpoint​

Everything in sections 1 and 2 goes to a single endpoint using POST:

POST https://mixu6sd8i0.execute-api.ap-south-1.amazonaws.com/calls-webhook-ingestion-handler

Which action you are performing is decided by the type field in the request body:

type valueActionDocumented in
(omit the field)Sync a call recordingSection 1
"disposition-status"Update customer status / custom fieldsSection 2

Authentication​

Send your API key in a header on every request:

x-zip-api-key: YOUR_API_KEY
HeaderRequiredNotes
x-zip-api-keyYesProvided by Zipteams during onboarding. Keep it secret — it identifies your organisation.
Content-TypeYesMust be application/json.

There is no other header to send. You do not need to pass your organisation id anywhere — it is derived from your API key.

Authentication errors​

StatusResponseMeaning
403{ "error": "No authorization header" }The x-zip-api-key header was missing.
401{ "error": "Incorrect API Key in Authorization Header" }The key is wrong, or has been revoked.

Request envelope​

Both sections 1 and 2 use the same envelope. data is always an array, so you can send several records in one request.

{
"type": "disposition-status",
"data": [
{ "...": "one record" },
{ "...": "another record" }
]
}
FieldTypeRequiredDescription
typestringNoOmit it to sync calls. Set it to "disposition-status" to update statuses instead.
dataarrayYesOne or more records. Each record is processed independently — one bad record does not stop the others.
Keep batches small

Each record in data is queued separately. Batches of up to 50 records per request work best. If you have more, split them across multiple requests.


Responses​

Success​

{
"message": "Data Received Successfully"
}

HTTP Status Code: 200 OK

Errors​

StatusResponseCause
400{ "error": "No body found" }The request had no body.
400{ "error": "Invalid JSON" }The body was not valid JSON. A common cause is a trailing comma or an unescaped quote.
403{ "error": "No authorization header" }Missing x-zip-api-key header.
401{ "error": "Incorrect API Key in Authorization Header" }Invalid API key.

Before you start: two one-time setup steps​

Two things must be configured on the Zipteams Dashboard before your data will sync. Both are done once, by an admin on your team.

1. Add your agents to Zipteams​

A call only syncs if the agent it belongs to already exists on Zipteams and is Active. This is the single most common reason calls silently do not appear.

To add agents:

  1. Go to Setup → Manage Team
  2. Click the Add button
  3. Enter one email, or several comma-separated emails, of the agents you want to onboard
  4. Scroll down — the new users appear in the Invited section
  5. Click Make All Active

Once they are Active, their calls will start syncing. Any call you send for an email that is not on Zipteams is dropped.

2. Create your custom fields (only if you use custom_fields)​

If you want to push your own data points into Zipteams (campaign name, lead source, policy number, anything), you do it through custom_fields. Each custom field needs an internal_name, which is generated by Zipteams — you cannot invent it yourself.

To create a field and get its internal_name:

  1. Go to Setup → Connect your CRM
  2. Scroll to the Enable Inbound Dynamic CRM Fields Mapping section
  3. Click + Add New Field
  4. Once saved, the internal_name is displayed on the same page, next to the field you just created

Internal names are generated in sequence — zt_custom_1, zt_custom_2, zt_custom_3 and so on. They are not derived from the label you typed, so always copy the value shown on the page rather than guessing it from the field name.

Copy that value and use it as the internal_name in your payload:

"custom_fields": [
{ "internal_name": "zt_custom_1", "value": "Google Ads" }
]
custom_fields vs metadata — what's the difference?

They look similar but do opposite things.

  • custom_fields — data you want to store in Zipteams. It becomes visible on the Zipteams dashboard and can be used in reports. Requires an internal_name created on the dashboard first.
  • metadata — data you want echoed back to you. Zipteams does not interpret it; it simply returns it untouched in the meta object of the Call Summary Callback. Use it to carry your own correlation ids (ticket id, campaign id, internal row id) through the async processing.

Send a value in custom_fields if you want to see it in Zipteams. Send it in metadata if your system needs it back.


Recording URLs​

Everything Zipteams does starts with the recording, so this is the field to get right.

  • recording_url must always be present. If it is missing or empty, nothing syncs — no customer is created, no analysis runs.
  • It must be publicly accessible. Zipteams fetches the file over plain HTTP(S) with no credentials. If the URL requires a login, a signed token that has already expired, or is behind a VPN, the fetch fails.
  • Supported formats: MP3, WAV, AAC, M4A, MP4.

If your recordings require IP whitelisting​

Some telephony providers restrict recording downloads to approved IPs. If that is your setup:

  1. Whitelist this Zipteams IP address:

    13.201.157.246
  2. Tell us to use it, by setting access_type in the call object:

    "call": {
    "id": "call_98231",
    "recording_url": "https://recordings.yourcompany.com/98231.mp3",
    "start_time": "2026-07-28T09:15:00Z",
    "phone_number": "+919876543210",
    "access_type": "whitelisted_ip"
    }

Both steps are needed. Whitelisting the IP without sending access_type: "whitelisted_ip" will not work, because the request will be made from our standard processing path instead of the whitelisted one.

If your recordings are publicly accessible, omit access_type entirely.

Whitelisting for the callbacks too

If your webhook endpoint (sections 3 and 4) also restricts inbound traffic by IP, we can send our callbacks from the same whitelisted address 13.201.157.246. This is not on by default — contact us and we will enable it for your workspace.


Common mistakes​

These are the issues that come up most often during integration. Each one is worth checking before you get in touch.

MistakeWhat happensFix
"callback_url": ""The whole record is rejected with an invalid-URL validation errorOmit the key entirely if you have no callback URL. An empty string is not a valid URL. The same applies to any other URL field.
Sending "end_time"Ignoredend_time is not needed. Zipteams derives the call duration from the recording itself. Do not send it.
Phone number in the wrong placeCustomer is not matched, or the record is rejectedIn Section 1 (call sync) the phone goes in call.phone_number. In Section 2 (status update) it goes in customer.phone_number. They are different objects.
Agent email not on ZipteamsCall is dropped silentlyAdd the agent under Setup → Manage Team and click Make All Active.
Inventing an internal_nameThe custom field value is not storedinternal_name must be created on the dashboard first — see step 2 above.
start_time without a timezoneThe call lands at the wrong timeAlways include a timezone designator — an offset (2026-07-28T14:45:00+05:30) or Z for UTC (2026-07-28T09:15:00Z). Both are accepted; neither is optional.
Reusing the same call.idThe second call is ignored as a duplicatecall.id must be unique for every call.
Recording URL behind authCall is created but no analysis appearsMake the URL public, or use IP whitelisting.

Why a call did not sync​

If a call returned 200 OK but never appeared in Zipteams, it will be one of these:

ReasonExplanation
Recording URL not presentcall.recording_url was empty or missing.
Call owner not found on ZipteamsNo Active Zipteams user matched agent.email (or agent.id) within your organisation.
Duplicate callA call with the same call.id had already been synced.
Maximum minutes reachedYour plan's processing minutes for the period are exhausted. Contact us to increase your limit.
Recording could not be fetchedThe URL was not reachable, needed credentials, or the file format is unsupported.
Neither phone nor email suppliedAt least one of call.phone_number or customer.email is required.

Support​

If something is still not working after checking the above, email support@zipteams.com with:

  • the exact JSON payload you sent,
  • the call.id values affected, and
  • the timestamp of the request.

That lets us trace the record end to end without a call.