Requests

The conventions every v2 endpoint shares — learn them once and the whole reference reads the same way.

Base URL

https://your-org-domain/kong/core/api/v2

Requests go through your organisation's platform host. An operation documented as /investors is called at https://your-org-domain/kong/core/api/v2/investors. Bodies are JSON (Content-Type: application/json) unless an operation says it takes multipart/form-data for a file upload.

Resources and IDs

  • Records are addressed by public ids — usually UUIDs. Some catalogue records (classifications, notes, banners, locations…) use whole-number ids; each path parameter says which.
  • Path parameters are named after what they identify — {userId}, {dealId} — never a bare id.
  • Lifecycle changes are a PATCH …/{id}/status with a status in the body, not verb endpoints.
  • Bulk operations live under …/bulk/… and take an array of ids.
  • Bring your own keys: investors, deals and other core records accept an external_id — your system's id for the record — so the two stay in step.

Pagination

List endpoints are cursor-paginated. Ask for up to 100 records with limit (default 25), then pass meta.next_cursor back as cursor — with the same filters, sort and limit — until it comes back null.

{
  "data": [ … ],
  "meta": { "limit": 25, "next_cursor": "eyJpZCI6…", "prev_cursor": null }
}

Cursors are opaque; don't build or edit them. A cursor that doesn't match the request returns 422 invalid_cursor. A few aggregate endpoints return a plain { "data": [ … ] } with no cursor — their pages say so.

Filtering

Filters use filter[field], with an optional operator:

FormMeaning
filter[status]=publishedEquals.
filter[status][in]=draft,publishedAny of a comma-separated list.
filter[status][not_in]=retiredNone of the list.
filter[created_at][gte]=2026-10-01Ranges on dates: gt, gte, lt, lte.
filter[folder_id][null]=trueHas no value.
filter[q]=riversideFree-text search over the fields the operation lists.

Each list operation documents which filters and operators it accepts.

Sorting, fields and includes

curl -G "$HELM_BASE/deals" \
-H "Authorization: Bearer $HELM_API_KEY" \
--data-urlencode "filter[status][in]=published,in_progress" \
--data-urlencode "filter[created_at][gte]=2026-10-01" \
--data-urlencode "sort=-updated_at,name" \
--data-urlencode "fields=name,status,currency" \
--data-urlencode "include=key_contacts"
  • sort — comma-separated fields from the operation's allowed list; prefix - for descending. The record id is always the final tie-break, so pages are stable.
  • fields — return only these top-level fields (id always comes back). Great for syncs and for keeping AI tool results small.
  • include — embed related records the operation offers, instead of making extra calls.

Safe retries with Idempotency-Key

Most writes accept an Idempotency-Key header. Send a fresh UUID with each new request and reuse it only when retrying that request — after a timeout, say. If the first attempt went through, you get its original response back instead of a duplicate. Keys are remembered for 24 hours.

curl -X POST "$HELM_BASE/investors" \
  -H "Authorization: Bearer $HELM_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3b1f6c1e-9a1d-4c55-8d7a-0c6c1f0f6a42" \
  -d '{ "email": "ada.lovelace@example.com", "first_name": "Ada", "last_name": "Lovelace" }'

Dry runs

Many writes take ?dry_run=true: the call is validated and run, then rolled back, and you get back what the real call would have returned with meta.dry_run set. Use it to check a payload — or let an AI assistant preview a change before you approve it.

Async jobs

Long-running work — large bulk creates, exports, imports — answers 202 Accepted with a job, and a Location header pointing at it. Poll GET /jobs/{id} until status is succeeded (read result) or failed (read error):

{
  "data": {
    "id": "4f2b9c1d-8a7e-4d3f-b2c1-6e5a4d3c2b1a",
    "type": "bulk_create",
    "status": "running",
    "progress": { "done": 1740, "total": 3480 },
    "result": null,
    "error": null
  }
}

A token sees only the jobs it started.

Deprecations

Operations replaced by a better one stay working until their sunset date and are marked Deprecated in this reference. Their responses carry Deprecation and Sunset headers and a Link to the successor, so you can find stragglers in your logs.