Registration — get an access-key / secret-key¶
This is the first thing a factory integrator does: register a factory-service
backend with TrustMint and obtain the access-key-id / secret-key pair that signs
every subsequent call. After this walkthrough you can drive the
Thing lifecycle, poll the API reference endpoints, and
wire up webhooks.
Credentials in this guide are placeholders. Wherever you see
<your-access-key-id>or<your-secret-key>, substitute the real values you capture from the 201 response. Never commit a real secret-key — the SDK examples write it to a git-ignored.aksk.env(see SDK quickstart).
Step 1 — register the factory-service (JWT-gated)¶
Registration itself is gated by a bearer JWT (a registrar-admin identity from the platform IdP), not by AK/SK — AK/SK does not exist yet at this point. Mint a registrar JWT against Keycloak, then:
POST /api/v1/factory-services
Authorization: Bearer <registrar-admin-jwt>
Content-Type: application/json
{
"registrar_id": "reg-acme-robotics",
"model_id": "550e8400-e29b-41d4-a716-446655440000",
"role": "identify",
"endpoint_url": "https://factory.example.com/v1/identify"
}
A 201 Created returns the one-time credential pair:
{
"id": "fs-...",
"registrar_id": "reg-acme-robotics",
"model_id": "550e8400-e29b-41d4-a716-446655440000",
"role": "identify",
"endpoint_url": "https://factory.example.com/v1/identify",
"access_key_id": "<your-access-key-id>",
"secret_access_key": "<your-secret-key>",
"state": "active",
"rotation_pending": false
}
role is only identify or provision. Register one backend per
(registrar_id, model_id, role) tuple you actually implement. endpoint_url is
the thingmake-to-factory HTTP backend URL for that role, not a device-facing DDI
endpoint. There is no platform default or registrar-wide fallback for a
model-bearing device.
The secret_access_key is shown exactly once. Capture it immediately; there is no
endpoint that re-reads it. The Go and Python 01-register-factory-service examples do
exactly this and persist the pair to .aksk.env — see SDK quickstart.
Where do AK/SK come from? Registration provisions a real DotID service user for your factory-service and issues it an access key through DotID’s service-user / access-key APIs. The
secret_access_keyis revealed exactly once in this 201 response — TrustMint never stores it (only theaccess_key_idplus the DotID handles are persisted; the plaintext secret column was removed in the v2.11 secret-de-storage cut). DotID is the issuing authority, and TrustMint holds no factory secret at rest. If you lose the secret you cannot re-read it — rotate the credential (which provisions a fresh access key with a short grace window, again returning the new secret reveal-once) and re-capture it.
If registration is rejected, the response is application/problem+json carrying a
THM-NNNNN code. The foundation-auth codes (THM-101xx — JWT expired / signature
invalid / missing) live in bucket 1; see the error catalog.
Step 2 — sign every later request (FGAI-HMAC-SHA256)¶
Once you hold <your-access-key-id> / <your-secret-key>, factory-service
runtime calls (/api/v1/things/*, /api/v1/state-changes,
/api/v1/identity-blacklist*, subscriptions) are authenticated with the
FGAI-HMAC-SHA256 scheme.
Registrar-administrative calls such as factory-service registration and the
newer device-model registry (/api/v1/thingmake/vendors,
/api/v1/thingmake/models, /api/v1/thingmake/software) are bearer-JWT gated
by the platform IdP/PDP. Keep that split visible in examples: use JWT to create
or administer registrar resources; use AK/SK for factory runtime callbacks and
feeds.
ℹ️
FGAI-HMAC-SHA256is the SigV4 algorithm — but not aws-sdk-compatibleThis is the AWS SigV4 derived-key-chain algorithm, so the SigV4 mental model applies directly: a
kDate→kRegion→kServicesigning-key chain, a canonical request, and anAuthorizationheader carryingCredential/SignedHeaders/Signature. BUT it is FGAI-branded — the chain terminates infgai4_request(not AWS’saws4_request) and the scheme name isFGAI-HMAC-SHA256(notAWS4-HMAC-SHA256). It is therefore NOT wire-compatible with the stockaws-sdkrequest-signer. Do not bolt anaws-sdksigner onto these endpoints — it will produce a signature DotID rejects. Use the FGAI SDK (below), which emits the FGAI-branded wire bytes.
Canonical request (six components, \n-joined — byte-identical to DotID’s
SigV4HmacVerifier.canonicalRequest):
canonical =
METHOD + "\n" +
CANONICAL_PATH + "\n" + // "/" when empty
CANONICAL_QUERY + "\n" + // sorted percent-encoded k=v, or "" when none
CANONICAL_HEADERS + "\n" + // each "name:value\n", names lower-cased + sorted
SIGNED_HEADERS + "\n" + // ";"-joined sorted lower-case names
SHA256_HEX(BODY)
where the signed header set is host;x-fgai-content-sha256;x-fgai-date.
Derived signing-key chain (then sign the canonical request with kSigning):
kSecret = "FGAI4" + <your-secret-key>
kDate = HMAC_SHA256(kSecret, <yyyyMMdd>)
kRegion = HMAC_SHA256(kDate, "us-east-1")
kService = HMAC_SHA256(kRegion, "thingmake")
kSigning = HMAC_SHA256(kService, "fgai4_request")
signature = HEX(HMAC_SHA256(kSigning, canonical))
The full recipe (with the frozen scope literals and the worked golden vector) is in
services/thingmake/sdks/testdata/README.md.
Headers sent on every signed request:
Header |
Value |
|---|---|
|
|
|
compact |
|
lower-case hex SHA-256 of the request body (equals canonical component 6) |
You should not hand-roll this. The SDK signers emit canonical strings byte-identical to the server’s verifier:
Go —
signing.NewSigningTransport(ak, sk, http.DefaultTransport)Python —
httpx.Client(auth=AKSKAuth(ak, sk))orrequests.Session()+AKSKAuthRequests(ak, sk)
See the SDK quickstart for the signing helpers and the
services/thingmake/sdks/README.md source.
When signing fails¶
Signing/auth failures return 401 with a factory-auth code (THM-201xx,
bucket 2 of the error catalog):
Code |
DotID failure mode |
Meaning |
Fix |
|---|---|---|---|
|
|
a required signing header ( |
attach all three signing headers |
|
|
the |
re-compute against the exact canonical request + derived key |
|
|
|
re-sign with a fresh |
|
|
access-key id in the |
confirm the AK is current + bound to an active factory-service |
|
|
a duplicate |
re-sign with a fresh |
(THM-20100 is the generic factory-auth-failed fallback for an unclassified
signing failure.)
The full bucket-2 table (titles + descriptions) is in the
error catalog, sourced from
../../services/thingmake/docs/errors/thingmake-error-catalog.md.
What next¶
Receive thing-state notifications → Webhooks
Run all four steps end-to-end → First hour
Self-certify your backend → Conformance