Skip to content

Conventions

Conventions that apply to every endpoint in the public API. Read this once; the per-resource pages assume you've internalized everything here.

Request format

  • Protocol: HTTPS only. Plain HTTP is refused.
  • Body: JSON, UTF-8. The Content-Type: application/json header is required on POST, PUT, and PATCH. Missing it returns 415 unsupported_media_type.
  • Body size limit: 5 MB. Larger payloads get back 413 Payload Too Large. For bulk imports of huge catalogs, use batch endpoints (max 500 items per call) or the streaming Imports API.
  • All responses are JSON, UTF-8.
bash
curl -X POST https://api.thehumind.com/public/v1/products \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "external_id": "SKU-123", "title": "..." }'

Identifiers

Every resource the public API exposes has two identifiers: one you control (external_id) and one Humind controls (humind_id). Pick the one that's most convenient for the call you're making.

IdentifierWho sets itFormatNotes
external_idYouFree-form string, unique per companyYour SKU, your slug, anything you can derive from your own data. Used for upserts: posting a product with the same external_id as an existing one updates that one.
humind_idHumind24-char lowercase hex stringReturned in every response. Stable for the lifetime of the resource.

For path parameters that take an {id} (GET /products/{id}, PATCH /products/{id}, …), pass either form:

FormExampleWhen to use
api:<external_id>api:SKU-123When you want to operate on a resource by your own identifier. The api: prefix disambiguates from humind_id.
<humind_id>65f1ab9c8e7d4a2b1c3d4e5fWhen you've stored the Humind ID from a previous response and want to use it directly.

Pick external_id for your scripts

If you're writing a sync script, external_id is almost always the right choice, your script already knows your SKU, and you don't have to round-trip through Humind to find the humind_id first.

Dates

All timestamps in responses are ISO 8601 in UTC with the trailing Z:

2026-04-25T14:30:00Z

In requests, any ISO 8601 timestamp is accepted; non-UTC inputs (e.g. 2026-04-25T16:30:00+02:00) are normalized to UTC at write time and stored with the Z suffix. We still recommend sending UTC client-side so what you read back exactly matches what you sent.

Pagination

List endpoints (GET /products, GET /collections, GET /knowledge) use opaque-cursor pagination. Each response carries a next_cursor string; pass it back as ?cursor=… to fetch the following page. Pages are capped at 100 items (default 50). When next_cursor is null, you've reached the end. The cursor is opaque — don't parse it, the format may change in a future version.

Idempotency

For every state-changing call (POST, PUT, PATCH, DELETE), include an Idempotency-Key header set to a UUID v4 (or any unique value, max 255 chars):

bash
curl -X POST https://api.thehumind.com/public/v1/products \
  -H "Authorization: Bearer hmd_live_..." \
  -H "Idempotency-Key: 3f1a8d92-7c4b-4e6f-b2a1-d5e9c8f7a3b4" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

What it does:

  • If your client retries the same request (same method + path + body) within 24 hours, the API replays the original response instead of executing the mutation a second time. Safe to retry on network blips, timeouts, gateway errors.
  • If you reuse the same key with a different body, the API rejects the request with 409 Conflict and code idempotency_conflict. Generate a fresh UUID for each new operation.

Required on every write

Idempotency-Key is required on every state-changing call (POST, PUT, PATCH, DELETE). Two state-machine-idempotent exceptions are documented inline: POST /imports/{sync_id}/start and POST /imports/{sync_id}/cancel accept the header but don't require it. Everything else returns 400 idempotency_key_required if the header is missing.

For batch endpoints, the idempotency key applies to the whole batch, a retry replays the entire 207 Multi-Status response.

Versioning

The API is URL-versioned. The current version is /public/v1.

  • Additive changes (new endpoints, new optional fields, new optional headers) ship under the existing version. Your code keeps working.
  • Breaking changes (renamed fields, removed endpoints, changed validation rules) ship under a new version (/public/v2). The previous version stays live in parallel.
  • Deprecation window: 6 months minimum between announcing a deprecation and removing it. We send notice to the email on file for the company and surface a banner in the dashboard.

A future version may introduce cursor-based pagination on list endpoints (?cursor=...&limit=... with { "data": [...], "next_cursor": "..." }). When that ships, clients that don't pass a cursor will keep working: the API will default to the largest reasonable page size.

The exact migration window for v2 will be announced in the changelog when v2 is on the roadmap.

Localization

The standard way to ship multilingual content is to embed it directly in the resource payload. Every resource has a default_language field plus an optional translations map keyed by ISO 639-1 codes:

json
{
  "default_language": "fr",
  "title": "Crème hydratante",
  "description": "...",
  "handle": "creme-hydratante",
  "translations": {
    "en": {
      "title": "Hydrating cream",
      "description": "...",
      "handle": "hydrating-cream"
    }
  }
}

The default_language value is the language of the top-level fields. translations[<lang>] is the per-locale override.

Language codes follow ISO 639-1 (lowercase, two letters): en, fr, de, es, it, nl, pt, ru, ar, he, zh.

Translations as a sub-resource

For translation workflows where each language ships on its own cadence, a dedicated translations sub-resource lets you patch one locale at a time without resending the full payload: see Products / Translations, Collections / Translations, and Knowledge / Translations.

Rate limits

Per-API-key limits are enforced today (separate buckets for reads, writes, and imports triggers), plus a 5/minute/IP throttle on failed auth attempts. See Rate limits for the active values, the 429 response shape, and backoff snippets.

Cross-tenant isolation

API keys are tightly bound to a single company. Trying to read or write a resource that belongs to another company always returns 404 Not Found (never 403): we don't leak the existence of other tenants' resources. This applies even when you happen to know a valid humind_id from another company.

Next

  • Errors: error format, HTTP status codes, Humind error codes.
  • Products: push your catalog.

Released under the proprietary Humind license.