POST
/
v1
/
orgs
/
{org_id}
/
workspaces
/
{workspace_id}
/
deployments
/
{deployment_id}
/
cohorts
/
upload
Upload Cohort
curl --request POST \
  --url https://apps.sarvam.ai/api/scheduling/v1/orgs/{org_id}/workspaces/{workspace_id}/deployments/{deployment_id}/cohorts/upload \
  --header 'Content-Type: multipart/form-data' \
  --header 'X-API-Key: <api-key>' \
  --form 'name=April Users Batch 1' \
  --form cohort_file='@example-file' \
  --form cohort_transformation_file='@example-file'
{
  "name": "April Users Batch 1",
  "cohort_id": "coh-x1y2z3",
  "status": "completed",
  "source_type": "file_upload",
  "result": {
    "total_records": 5000,
    "valid_records": 4850,
    "rejected_records": 150
  },
  "created_by": "user@company.com",
  "created_at": "2026-04-01T09:00:00Z",
  "updated_by": null,
  "updated_at": "2026-04-01T09:02:30Z"
}

Overview

A cohort gives your deployment user context. When a known user calls in, the agent receives their personalized variables (name, balance, language preference, etc.) — making the conversation feel tailored rather than generic.

How phone number matching works

The phone number is the lookup key. When an inbound call arrives, the system:
  1. Extracts the caller’s phone number
  2. Looks it up across all cohorts uploaded to this deployment
  3. If found → loads that user’s agent variables into the conversation
  4. If not found → the agent handles the call without any personalized context
This means your CSV must include a phone number column — it’s how the system connects “this caller” to “this row of data.”

Multiple cohorts with the same phone number

If you upload multiple cohorts and the same phone number appears in more than one, the most recently uploaded cohort takes precedence. The system always uses the latest context for a given phone number. This is useful when you need to refresh user data — simply upload a new cohort with updated values. You don’t need to delete the old one.
ScenarioWhat happens
Phone number in one cohortThat cohort’s variables are used
Phone number in multiple cohortsThe latest cohort’s variables are used
Phone number not in any cohortAgent handles the call without personalized context

Transformation config

The transformation config tells the system how to read your CSV:
{
  "phone_number": { "column_name": "mobile", "country_code": "IN" },
  "app_variables": {
    "customer_name": { "column_name": "name" },
    "outstanding_amount": { "column_name": "balance" },
    "due_date": { "column_name": "payment_due" }
  },
  "app_overrides": {
    "initial_language_name": { "column_name": "preferred_language" }
  }
}
SectionPurpose
phone_numberRequired. Which column contains the user’s phone number. This is the key used to match inbound callers.
app_variablesMaps CSV columns → agent variables. Keys must match the agent’s declared variables.
app_overridesOverride agent-level settings per user (language, initial message, initial state)

Phone number normalization

The system normalizes all phone numbers to E.164 format using the country_code you provide. For example, with "country_code": "IN":
  • 9876543210+919876543210
  • 09876543210+919876543210
  • +919876543210+919876543210 (already valid)
This ensures matching works correctly regardless of how the number is formatted in your CSV.

Validation

Blocking — rejects the entire upload:
  • All referenced column_name values must exist as CSV headers
  • CSV must have at least one data row
  • app_overrides keys must be one of: initial_bot_message, initial_state_name, initial_language_name
  • app_variables keys must match the agent’s declared variables
Row-level — individual rows are rejected, the rest continue:
  • Phone number must be valid (normalizable to E.164)
  • Required columns must be non-empty
  • Formatting functions (if configured) must succeed

Statuses

StatusMeaning
processingUpload queued and being validated
completedProcessing finished — user context is live
failedProcessing failed (upload-level error)

Checking for rejected records

After status becomes completed, check result.rejected_records:
GET /deployments/{id}/cohorts/{cohort_id}
If result.rejected_records > 0, download the rejection file to see which rows failed and why:
GET /deployments/{id}/cohorts/{cohort_id}/files?file_type=rejected_records
Fix the data issues in your CSV and re-upload. Rejected users won’t have personalized context available when they call.

Authorizations

X-API-Key
string
header
required

Path Parameters

org_id
string
required
workspace_id
string
required
deployment_id
string
required

Body

multipart/form-data

Multipart form data for uploading a cohort.

name
string
required

Cohort name (1-50 characters)

Maximum string length: 50
Pattern: ^[\w\- ]{1,50}$
cohort_file
file
required

CSV file containing the cohort data

cohort_transformation_file
file
required

JSON file defining how CSV columns map to agent variables

Response

Successful Response

Cohort metadata including processing status and result counts.

name
string
required

Name of the cohort

cohort_id
string
required

Unique identifier for the cohort

Example:

"coh-x1y2z3"

status
enum<string>
required

Current processing status

Available options:
processing,
completed,
failed
source_type
enum<string>
required

How the cohort was uploaded

Available options:
pre_signed_url,
file_upload
created_by
string
required

User who created this cohort

Example:

"user@company.com"

created_at
string<date-time>
required

Timestamp when created (ISO 8601)

Example:

"2026-04-01T09:00:00Z"

updated_at
string<date-time>
required

Timestamp when last updated (ISO 8601)

Example:

"2026-04-01T09:02:30Z"

result
CohortResult · object

Processing result with record counts

updated_by
string | null

User who last updated this cohort