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.