Get started

Requests and responses

JSON in, JSON out, over HTTPS. This page covers the conventions every endpoint shares: ids, times, money, partial updates, languages and request ids.

JSON

  • Send request bodies as one JSON object with Content-Type: application/json. Responses are application/json; charset=utf-8.
  • Bodies are limited to 1 MB (body_too_large).
  • Unknown fields are rejected, not ignored: a misspelled field answers 400 unknown_field with the field named in fields. Send only the fields an endpoint documents, never whole objects copied from a response.
  • A value of the wrong type (a string where a number is expected) answers 400 bad_json.
  • Creating returns 201 Created with the new object. Reading and changing return 200 OK. Deleting returns 200 OK with a small confirmation such as {"ok": true, "id": "lead_…"} or {"id": "hook_…", "deleted": true}.

Ids

Every id is a string made of a type prefix, an underscore and 26 lowercase letters and digits, for example lead_01j8z7c2d4f6g8h0j2k4m6n8p0. The prefix tells you what the id points to:

PrefixObjectPrefixObject
lead_Leadtask_Task
contact_Contactnote_Note
company_Companyinvoice_Invoice
pipeline_Pipelineproduct_Product
stage_Stagefield_Custom field
conv_Conversationmsg_Message
channel_Channelmember_Member of the workspace
hook_Webhookdlv_Webhook delivery
key_API keyws_Workspace
app_App (its OAuth client id)inst_App installation

Ids are sortable by creation time and never reused. Treat them as opaque strings: store them as they are and compare them exactly. Leads also have a human number (#1042) that is unique in the workspace.

An id of the wrong type in a path answers 404 not_found or 400 invalid_id_type.

Times

Times are RFC 3339 strings with fractional seconds, for example "2026-09-27T09:41:12.482913Z". Use a real RFC 3339 parser: the number of fractional digits varies. Fields that can be empty are null, for example closed_at of an open lead. When you send a time (a task's due_at), include the offset.

Money

Amounts are integers in the smallest unit of their currency, next to a three-letter currency code. For Uzbek soʻm that unit is the tiyin: 1 soʻm is 100 tiyin, so 1,500,000 soʻm is sent and returned as 150000000.

json
{ "amount": 150000000, "currency": "UZS" }

This applies to a lead's amount, a product's price, and an invoice's amount, paid_amount and line price. Never send amounts as decimals or strings. A lead without a currency uses the workspace's currency.

Partial updates

PATCH changes only the fields you send; every other field keeps its value.

  • To clear a reference such as a lead's owner_id, contact_id or company_id, send it as null.
  • custom holds the values of custom fields, keyed by the field's key. In a PATCH, only the keys you send change.
  • Names that Kweko shows in several languages (pipelines, stages, loss reasons, field labels) are objects keyed by locale, for example {"uz-Latn": "Yangi", "ru": "Новая", "en": "New"}. When you write one, you can send a plain string: it is used for every language.

Deleting and restoring

Deleting a lead, contact or company moves it to the trash: it disappears from lists, reading it answers 410 gone with deleted_at, and POST /v1/{leads|contacts|companies}/{id}/restore brings it back.

Languages

Error messages and a few labels follow the Accept-Language header: English (en, the default), Russian (ru) or Uzbek (uz). Codes such as validation_failed and field names never change with the language, so branch on codes, not on messages.

Request ids

Every response has an X-Request-Id header, and every error body repeats it as request_id. Quote it when you contact support. You can send your own X-Request-Id (up to 64 letters, digits, -, _ or .) to trace a call across your systems; Kweko uses and returns it.

Retries and idempotency

The API has no general Idempotency-Key header yet.

  • GET requests are always safe to retry.
  • Sending a message accepts a client_id (up to 64 characters): a retry with the same client_id returns the message that was already queued instead of sending it twice. See Conversations.
  • For other writes, a retry after a timeout can create a duplicate. Look the record up first (for example by your own reference in source or a custom field) or accept the rare duplicate.
  • Retry 429 and 5xx answers with exponential backoff; for 429, wait at least Retry-After seconds.

Versioning

The version is in the path (/v1). Within v1, new fields, endpoints, event types and error codes can appear at any time; changes that would break an integration are meant for a new version. Write your code to ignore unknown fields and to handle unknown error codes by their HTTP status. Changes are listed in the changelog.