KasarKasar Docs
API Reference

Import / Export

Import records in batch and export data as CSV or JSON. Admin-only endpoints for data management.

The import and export endpoints allow administrators to move data in and out of Kasar in bulk. Both endpoints require admin privileges.

Import Records

POST /api/v1/import/{object}

Batch import records into an object in a single call. Each record is created through the standard object service, so pipeline defaults (pipeline, step, and step-field defaults) are automatically applied for objects with a pipeline. Records are created sequentially. A record whose creation hits a unique-constraint violation is counted as a duplicate rather than failing the request.

This endpoint is restricted to admin users. Non-admin tokens receive a PERMISSION_DENIED error with HTTP status 400.

Path Parameters

ParameterTypeDescription
objectstringThe object to import into (e.g. contacts, companies)

Request Body

{
  "records": [
    {
      "first_name": "Alice",
      "last_name": "Martin",
      "email": "alice@example.com",
      "company_name": "Acme Corp"
    },
    {
      "first_name": "Bob",
      "last_name": "Dupont",
      "email": "bob@startup.io"
    }
  ]
}
FieldTypeDescription
recordsobject[]Required, non-empty. Array of records to import. Each record is a key-value map matching the object's field names.
add_to_list_idsstring[]Optional. Adds every created record to these existing lists (per-list outcome in lists). Duplicates and failed rows are excluded.
create_list_namestringOptional. Creates a new list with this name and adds every created record to it — import + list in one call.

Limits

  • Max duration: 300 seconds (5 minutes)

Example Request

curl -X POST "https://kasar.app/api/v1/import/contacts" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "records": [
      {
        "first_name": "Alice",
        "last_name": "Martin",
        "email": "alice@example.com"
      },
      {
        "first_name": "Bob",
        "last_name": "Dupont",
        "email": "bob@startup.io"
      }
    ]
  }'

Response

{
  "object_name": "contacts",
  "created": 1,
  "created_ids": ["b1f2c3d4-0000-4a5b-8c9d-1e2f3a4b5c6d"],
  "duplicates": 1,
  "failed": 0,
  "errors": []
}
FieldTypeDescription
object_namestringThe object that was imported into
createdintegerNumber of records successfully created
created_idsstring[]IDs of every created record
duplicatesintegerNumber of records skipped because creation hit a unique-constraint violation
failedintegerNumber of records that failed for any other reason
errorsobject[]Details for each failed record, up to 100 entries: { index, error }

When add_to_list_ids or create_list_name is supplied and at least one record was created, the response also includes list-membership fields:

FieldTypeDescription
listsobject[]Per-list outcome for the created records that were added
created_listobjectPresent when create_list_name succeeded — the newly created list
create_list_errorstringPresent when create_list_name could not be created

Duplicate Detection

A record counts as a duplicate only when its insert violates a unique constraint on the object (PostgreSQL error 23505, e.g. a unique email). These rows are not created and are counted in the duplicates field — they are not included in created_ids and are excluded from add_to_list_ids / create_list_name.

Error Example

When some records fail for a non-duplicate reason (validation, missing relation, etc.):

{
  "object_name": "contacts",
  "created": 1,
  "created_ids": ["b1f2c3d4-0000-4a5b-8c9d-1e2f3a4b5c6d"],
  "duplicates": 0,
  "failed": 1,
  "errors": [
    {
      "index": 1,
      "error": "Field 'email' must be a valid email address"
    }
  ]
}

Each entry in errors is { index, error } — the zero-based index of the record in the request and the error message. There is no per-row code field.

Error Responses

StatusCodeDescription
400PERMISSION_DENIEDToken does not belong to an admin user, or the caller lacks create permission on the object
400INVALID_OBJECTThe object name does not exist
400MISSING_REQUIRED_FIELDThe records array is missing or empty
401UNAUTHORIZEDInvalid or missing Bearer token

Export Records

GET /api/v1/export/{object}

Export records from an object as JSON or CSV. Supports filtering, sorting, and field selection. Record references (relation / rollup UUIDs) are resolved to their display value before export — raw UUIDs are never returned.

This endpoint is restricted to admin users. Non-admin tokens receive a PERMISSION_DENIED error with HTTP status 400.

Path Parameters

ParameterTypeDescription
objectstringThe object to export (e.g. contacts, companies)

Query Parameters

ParameterTypeDefaultDescription
formatstringjsonExport format: json or csv
fieldsstringall fieldsComma-separated list of field names to include. When omitted, internal/noise columns (search_vector, cached_data, raw_metadata, raw_data) are stripped; an explicit fields request is honoured verbatim.
filter_fieldstringField name for a single inline filter
filter_operatorstringFilter operator. Use the internal operator names, e.g. equals, not_equals, contains, in, greater_than, less_than, greater_equal, less_equal, is_null, is_not_null. With in, pass a comma-separated filter_value.
filter_valuestringFilter value for filter_field / filter_operator
filtersstringAdvanced filters as a JSON-encoded FilterGroup object. When both filter_field and filters are supplied, they are combined with AND.
sort_bystringField to sort by. When omitted, no explicit ordering is applied.
sort_dirstringascSort direction: asc or desc (only used when sort_by is set)
limitinteger5000Maximum records to export (capped at 10000)

Example: Export as JSON

curl -X GET "https://kasar.app/api/v1/export/contacts?format=json&fields=first_name,last_name,email&limit=500" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..."

Response:

{
  "format": "json",
  "records": [
    {
      "first_name": "Alice",
      "last_name": "Martin",
      "email": "alice@example.com"
    },
    {
      "first_name": "Bob",
      "last_name": "Dupont",
      "email": "bob@startup.io"
    }
  ],
  "total": 2
}
FieldTypeDescription
formatstringAlways json for this response
recordsobject[]The exported records
totalintegerNumber of records returned

Example: Export as CSV

curl -X GET "https://kasar.app/api/v1/export/contacts?format=csv&fields=first_name,last_name,email" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..." \
  -o contacts.csv

When format=csv, the response body is the raw CSV text (not a JSON envelope) with:

  • Content-Type: text/csv; charset=utf-8
  • Content-Disposition: attachment; filename="contacts_export.csv" (filename is {object}_export.csv)

Cell values are flattened to a single readable string: relation/display objects render their display label, CURRENCY renders amount currency_code, ADDRESS renders its formatted value, and arrays (M2M relations, MULTI_SELECT) are joined with ; .

Example: Export with Filters

curl -X GET "https://kasar.app/api/v1/export/contacts?format=json&filter_field=status&filter_operator=equals&filter_value=qualified&sort_by=last_name&sort_dir=asc" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..."

For complex filters, use the filters parameter with a JSON-encoded FilterGroup:

curl -G "https://kasar.app/api/v1/export/contacts" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..." \
  --data-urlencode 'format=json' \
  --data-urlencode 'filters={"type":"AND","conditions":[{"field":"status","operator":"equals","value":"qualified"},{"field":"created_at","operator":"date_after","value":"2025-01-01"}]}'

A FilterGroup has type ("AND" or "OR") and a conditions array of { field, operator, value } conditions (or nested groups). Invalid JSON in filters is ignored.

Error Responses

StatusCodeDescription
400PERMISSION_DENIEDToken does not belong to an admin user
400INVALID_OBJECTThe object name does not exist or is not readable
401UNAUTHORIZEDInvalid or missing Bearer token

On this page