Getting started¶
This is the zero-to-registered journey: five linear steps that take a brand-new integrator from nothing to a factory-service backend that registers, self-certifies, receives notifications, and polls state-changes. Each step links the relevant SDK example and the error catalog entry you will hit if something is wrong.
Prerequisite — one base URL, one credential¶
Everything trustmint exposes to you is reached over HTTPS at a single host:
Host |
What it serves |
|---|---|
|
the trustmint capability API — the surface this guide uses |
|
the same API, one release ahead, for integration testing |
|
the browser consoles, if you would rather click than call |
Paths are capability paths, not service names: /provisioning/v1/… (registrars,
enrollment, factory services, thing lifecycle, state changes), /access/v1/…
(repositories, scopes, grants), /telemetry/v1, /twins/v1/…, /rules/v1/…,
/pki/v1/…. The CLI reference lists every group, and the
API reference renders the generated specification.
Two credential kinds exist, and you will use both in this guide:
an interactive bearer token from your account’s SSO login, used once to register your backend;
an access-key / secret-key pair issued by that registration, which signs every call afterwards with the FGAI-HMAC scheme (FGAI4 derived key — not AWS SigV4). See Registration.
Step 0 — Prove you can reach the API¶
Two endpoints under /pki/v1/ are public trust-anchor discovery and need no
credential, so they are the cleanest first request: a 200 here proves DNS, TLS
and routing before any signing question can confuse the diagnosis.
curl -fsS https://api.flexgalaxy.ai/pki/v1/jwks
curl -fsS https://api.flexgalaxy.ai/pki/v1/ca
The first returns a JWKS document — a keys array whose entries carry kty, alg
and kid — used to verify signed artifacts such as the identity-blacklist snapshot.
The second returns the PEM certificate chain your devices pin. If either fails, stop
here: no later step can succeed. If they succeed, the platform is reachable and every
remaining failure is about your credential or your payload.
Step 1 — Register a factory-service¶
Ordering (required for the lifecycle verbs).
POST …/things/{id}/provision,…/activateand…/deactivateare served by aprovision-role factory service. The row must be the one thingmake resolves for that thing: a model-bound thing (enrolled by model UUID) is served by an ACTIVEprovisionrow carrying that exactmodel_id; a model-less thing falls back to the registrar-level row (model_idnull — not creatable throughPOST …/factory-services). If the resolved row does not exist, thingmake refuses the verb before changing anything, with409and codeTHM-40200; the thing’s state and its saga count are untouched, so you can register the backend and retry. Anidentify-role registration does not satisfy this: register theprovisionrole as well ("role":"provision"with"model_id"— the create API requires it) and confirm it is ACTIVE before driving provision/activate/deactivate.
Who runs it: an administrator of the registrar’s owning account — the account root, or a user with account-administrator access — because the call is authorized against that registrar’s account, not against your identity globally (a caller from any other account is refused).
Before it can succeed — grant the platform provisioning trust (one-time, self-serve).
Registering a factory service makes the platform provision a service user and an access
key inside your account on your behalf, so you grant that capability first. Sign in to
https://console.flexgalaxy.ai as the account root, then run the two grant calls below.
You need two things from that sign-in:
your bearer token — today there is no console button or CLI login that prints it: copy the session token from your signed-in browser session (developer tools → storage), or mint it programmatically through the SSO PKCE flow. A first-class consent surface is tracked as a platform improvement.
your account context id — one call, shown below.
ACCOUNT=<your-account-id>
# 1) bearer -> account context id (pick the entry with "type":"account"; its context_id is $CTX)
curl -fsS https://api.flexgalaxy.ai/identity/v1/contexts \
-H "Authorization: Bearer $BEARER"
# 2) grant: create service users
curl -fsS -X POST https://api.flexgalaxy.ai/identity/v1/accounts/$ACCOUNT/trust-policies \
-H "Authorization: Bearer $BEARER" -H "X-Session-Context-Id: $CTX" \
-H 'Content-Type: application/json' \
-d '{"target_resource_frn":"frn:'"$ACCOUNT"':iam:user/*","source_account_id":"00000000-0000-0000-0000-000000000000","granted_actions":["iam:User:CreateServiceUser"],"service_namespace":"thingmake"}'
# 3) grant: the access keys for those service users
curl -fsS -X POST https://api.flexgalaxy.ai/identity/v1/accounts/$ACCOUNT/trust-policies \
-H "Authorization: Bearer $BEARER" -H "X-Session-Context-Id: $CTX" \
-H 'Content-Type: application/json' \
-d '{"target_resource_frn":"frn:'"$ACCOUNT"':iam:credential/*","source_account_id":"00000000-0000-0000-0000-000000000000","granted_actions":["iam:AccessKeyAdmin"],"service_namespace":"thingmake"}'
What this grants, honestly: it allows FlexGalaxy platform provisioning services to create service users and access keys in your account; it is used by ThingMake factory provisioning and is not limited to a single product name.
Revoke any time — GET the same path to list the rows and their ids, then
DELETE /identity/v1/accounts/$ACCOUNT/trust-policies/{id} with the same two headers.
After revocation, factory-service registration is refused with 403 and code
THM-20200 (“ThingMake provisioning trust not granted for this account”) on its next
attempt; re-grant to restore it.
First get your account credential and create the registrar your factory targets — the
console service-user path in Registration §Step 0 — then use the
registrar-admin bearer to POST /provisioning/v1/factory-services and capture your
one-time <your-access-key-id> / <your-secret-key>. Full walkthrough:
Registration.
curl -fsS -X POST https://api.flexgalaxy.ai/provisioning/v1/factory-services \
-H "Authorization: Bearer <registrar-admin-token>" \
-H 'Content-Type: application/json' \
-d '{"registrar_id":"reg-acme-robotics",
"model_id":"550e8400-e29b-41d4-a716-446655440000",
"role":"identify",
"endpoint_url":"https://factory.example.com/v1/identify"}'
SDK example:
01-register-factory-service(Go + Python) does exactly this and writes the pair to a git-ignored.aksk.env.The secret key is shown exactly once. No endpoint re-reads it; if you lose it, rotate the credential rather than re-registering.
If it fails: this endpoint is token-gated, so failures are foundation-auth codes — bucket 1 of the error catalog (
THM-10100token expired,THM-10110signature invalid,THM-10120token missing). The AK/SK signing codes (bucket 2,THM-201xx) apply to the signed requests in later steps, not to this bearer-token call — see Registration for the full split.
Step 2 — Make your first signed call¶
Confirm the pair works before you build anything on it. Sign a read with FGAI-HMAC —
the SDKs and the fgai CLI both do the signing for you. The CLI is published on
dl.flexgalaxy.ai for macOS, Linux and Windows:
curl -fsSL https://dl.flexgalaxy.ai/fgai/install.sh | bash
fgai configure # stores the access key / secret key in a profile
fgai provisioning factory-services-list
A 200 with your own factory-service in the list means the credential, the signing
scheme and the clock skew window are all correct. A THM-201xx means the signature
did not verify — Registration documents the canonical string-to-sign.
Step 3 — Unlock device enrollment (factory capability)¶
Enrolling device identities is a separate, explicitly granted capability — it is not implied by an account-administrator policy, and it is not switched on by approval alone. The order is:
Request the factory capability for your account:
fgai provisioning factory-registrations-create(or ask your platform contact to file it on your behalf). The request is recorded as the approval object.We approve it (platform ops) — you are notified when it is on.
Attach
ThingMakeEnrollAccessto the service-user credential your provisioning runs under — your account’s root/admin does this in the console (Service user → Access policies → attach), and it is an explicit attachment: a broad administrator grant does not confer it.Enroll — pass the model’s UUID, not its
vid:piddescriptor. See it withfgai registry models-list(theidfield of the model you registered in Device models, or of themodels-createresponse):fgai provisioning enrollments-create --body '{"registrar_id":"…","thing_id":"<serial>","model":"<model-uuid>"}'→ the response carries the realthing_idyour device will present. The distinction is load-bearing: enrollment resolves a model by UUID only, so a bare descriptor ("model":"<pid>") leaves the thing model-less — and a model-less thing has no API path to aprovisionbackend, becausePOST …/factory-servicesrequires amodel_id. Enroll by UUID so the thing is model-bound and theprovisionrow you register for thatmodel_idcan serve it.Provision + connect — the device SDK runs identify → provision (CSR) → mTLS against your regional plane; see Device SDKs.
A missing capability is refused with THM-10140 naming exactly
ThingMakeEnrollAccess; THM-30170 means the capability request has not been filed yet.
Step 4 — Place the thing into your repository¶
Enrollment creates the thing; it does not, on its own, make the thing readable to
you. The account’s home reference is created when the thing is placed into a
repository — until then an owner-side read refuses with 404 thing not found and
attribute or telemetry reads have no reference to authorize against. See
Thing access model for what the reference governs.
Place the thing from the console (Repositories → open the target repository → place), or with the CLI. The default repository is materialized on first touch, so list repositories first, then place:
fgai access repositories-list
fgai access repositories-things --repository <repository-id> \
--body '{"thing_id":"<thing-id>","joined_via":"user"}'
Verify the reference exists:
fgai access things-owner --thing <thing-id>
→ 200 with home_repository_id, owner_account_id and thing_id. Placing the
same pair again is idempotent (ok).
Step 5 — Run the conformance suite against your backend¶
Self-certify that your backend implements the contract correctly before you wire it
into anything. Point your backend’s thingmake-base-url at the suite’s
--listen-addr (default :8910), then run the single command. Full walkthrough:
Conformance.
thingmake-conformance \
--backend-url http://your-factory-backend:8080 \
--access-key <your-access-key-id> \
--secret-key <your-secret-key>
Exit
0means every scenario passed.If it fails: registrar-lifecycle + thing-state-machine codes — buckets 3 and 4 of the error catalog (
THM-30xxx,THM-40110illegal transition,THM-40120missing Idempotency-Key). The suite names the expectedTHM-NNNNNin each failure diagnostic.
Step 6 — Receive a thing-state notification¶
Subscribe to notifications and host an HMAC-verifying receiver so a state-change is pushed to you. Full walkthrough: Webhooks.
fgai provisioning state-change-subscriptions-create --body '{
"target_url": "https://factory.example.com/hooks/thing-state",
"acknowledge_polling_still_mandatory": true }'
SDK example:
02-receive-state-notification(subscription + listener) and04-verify-webhook(HMAC verify helper).Remember:
acknowledge_polling_still_mandatory=trueis required — a subscription does not replace polling.If it fails: subscriptions codes — bucket 6 of the error catalog (
THM-60110polling not acknowledged,THM-60120non-https target_url,THM-60140invalid event_filter).
Step 7 — Poll the state-changes feed¶
Webhooks are best-effort; the durable backstop is the cursor-paged feed. Poll
GET /provisioning/v1/state-changes?since=<next_cursor> and persist next_cursor
between calls. See the state-changes group in the API reference.
SDK example:
03-poll-state-changes(cursor loop).If it fails: state-changes-feed codes — bucket 5 of the error catalog. Most importantly
THM-50120— a cursor older than 72h returns HTTP 410 and you must full-sync viaGET /provisioning/v1/things, then resume polling. AlsoTHM-50100(drop?registrar_id=) andTHM-50110(malformed cursor).
What next¶
You now have a backend that registers, certifies, subscribes, and polls. From here:
Deepen each step → Registration · Conformance · Webhooks
The endpoint contracts → API reference
Every command, grouped by capability → CLI reference
The lifecycle these notifications report → Thing lifecycle
The device-facing wire contract → DDI-1 contract
Decode any error → Error catalog