Changelog
This log records changes to the TrakRF public API under /api/v1/ that affect integrators. Changes to the first-party web app, internal-only endpoints, or anything behind session cookies (see Private endpoints) are out of scope here.
Entries follow the Keep a Changelog convention with the v1 stability commitment in Versioning: within v1, changes are additive only — no silent breaking changes. Deprecations are flagged at least six months before sunset via RFC 8594 headers.
Each entry covers:
- Added — new endpoints, fields, parameters, or enum values
- Deprecated — surface that still works but is scheduled for removal (includes sunset date)
- Removed — surface past its sunset date (major version only)
- Fixed — corrections that align shipped behavior with documented behavior and do not change the contract
Unreleased
Tracked but not yet in a release tag. Merged changes land here first, then move to a dated section on each platform release.
Added
POST /api/v1/locationsnow acceptsparent_identifier(natural key) to create a child location in one call. Previously the only parent field (parent_location_id, an internal numeric FK) was not exposed to API consumers, and parent-related payload keys were silently ignored. See the updated request schema in the API reference.POST /api/v1/inventory/savenow acceptslocation_identifier(string) andasset_identifiers(string array), matching the identifier convention used everywhere else in the v1 surface. The numericlocation_id/asset_idsfields still work for backward compatibility but are no longer shown in the published spec.- The
typefield on assets enumerates its allowed values (asset,person,inventory) in the OpenAPI spec, and validation errors on unknown values return the allowed set in thefields[].paramsobject. POST /api/v1/orgs/{id}/api-keys,GET /api/v1/orgs/{id}/api-keys, andDELETE /api/v1/orgs/{id}/api-keys/{keyID}are now public, authenticated with the newkeys:adminscope (or a session JWT from an org administrator). Akeys:adminkey may mint anotherkeys:adminkey, enabling unattended rotation for iPaaS, CI/CD, and IaC workflows. See Authentication → Programmatic key rotation.DELETE /api/v1/orgs/{id}/api-keys/{keyID}now accepts either the integer surrogateidor the UUIDjtifor{keyID}— both forms revoke the same key. Documented in Authentication → Identifying a key (TRA-501, TRA-504).- Pagination envelope (
limit,offset,total_count) added onGET /api/v1/locations/{identifier}/{ancestors,children,descendants},GET /api/v1/orgs/{id}/api-keys, andGET /api/v1/assets/{identifier}/history. Every list endpoint now uses the standard envelope; the previous "non-paginated exceptions" carve-out on the Pagination page has been removed (TRA-503, TRA-504).
Changed
- API quickstart and Getting-started → API pages now auto-detect environment from the docs hostname (
docs.trakrf.id→ production app,docs.preview.trakrf.id→ preview app), with a switcher for cross-environment readers (TRA-467 — F4). - Added a multi-organization warning on the API-key minting steps: keys are scoped to whichever org is selected in the avatar menu at creation time (TRA-467 — F5).
- Added a UI-form-to-scope-string mapping table on Authentication → Scopes (TRA-467 — F6).
- Errors → Envelope clarified that
titleis descriptive and varies; clients should match ontype(TRA-467 — F7). - Added Date fields — a new API-reference page documenting the
valid_from/valid_toconvention:valid_fromalways present as RFC3339,valid_toomitted when unset, inboundFlexibleDateparsing with US-first slash-date ambiguity warning (TRA-472). - API quickstart step 5 ("Mint an API key") now names the Expires picker, enumerates its options (Never / 30 days / 90 days / 1 year / Custom), and recommends 90 days as the production default (TRA-449, TRA-504).
- Errors now documents the optional
paramsobject onvalidation_error.fields[]entries — field-specific constraint metadata such asmax_length,allowed_values,min,max. The field has shipped for some time but was undocumented in the API reference (TRA-504).
Fixed
X-RateLimit-Remainingnow stays bounded byX-RateLimit-Limit(per IETF draft-ietf-httpapi-ratelimit-headers). Previously a fresh key could returnremaining=119againstlimit=60, because the header surfaced the internal burst-bucket size instead of advertised quota. The burst safety margin still exists — it's just hidden from the header, where it only confused clients.X-RateLimit-Resetis now the wall-clock time at whichRemainingwill next equalLimit, rather than the time at which the internal bucket refills to burst. Previouslyresetcrept forward by one second on every request, makingsleep(reset - now)a zero-second no-op that defeated the back-pressure signal. Clients that respected the header were, in effect, not being told when to pause.GET /api/v1/locations/{identifier}/ancestors,/children, and/descendantsnow populate theparentfield with the parent's natural key (omitted on root nodes), matchingGET /api/v1/locations/{identifier}andGET /api/v1/locations. Previously every node returnedparent: nullregardless of depth.GET /api/v1/locations/{identifier}/ancestors,/children, and/descendantsnow accept API-key auth withlocations:readscope, matching the other location reads. Previously these sub-routes were registered on the session-auth router only, so valid API keys returned401with a misleading "Bearer token is invalid or expired" message.POST /api/v1/assetsnow defaultsis_activetotruewhen the field is omitted, so API-created assets appear in the defaultGET /api/v1/assetslist view without an extra round-trip. Previously omitted fields hit the Go zero value (false) and the newly created asset was hidden.POST /api/v1/assetsandPOST /api/v1/locationsnow defaultvalid_fromto the current time when the field is omitted. Previously omitted fields hit the Go zero value (0001-01-01T00:00:00Z), which surfaced as an invalid-looking date in responses.valid_fromandvalid_tonow follow a single convention across every resource:valid_fromis always present as RFC3339 UTC,valid_tois omitted from responses when the record has no expiry. Zero-time (0001-01-01T00:00:00Z) and far-future sentinels (2099-12-31T...) no longer appear on the wire, and no response returns"valid_to": null. Existing rows were backfilled by a one-way migration (TRA-468).
v1.0.0 — 2026-04-20
Initial public availability. The /api/v1/ surface launches with API-key authentication, per-key rate limiting, read and write endpoints for assets and locations, and the generated OpenAPI reference.
Added
- API-key authentication — JWT-based keys minted from Settings → API Keys at app.trakrf.id, sent as
Authorization: Bearer <jwt>. Scoped per endpoint family (assets:read,assets:write,locations:read,locations:write,scans:read). See Authentication. - Read endpoints for the core resources:
GET /api/v1/assets,GET /api/v1/assets/{identifier},GET /api/v1/assets/{identifier}/historyGET /api/v1/locations,GET /api/v1/locations/{identifier}GET /api/v1/locations/{identifier}/ancestors,/children,/descendantsGET /api/v1/locations/current— snapshot of where each asset was last seen
- Write endpoints for assets and locations:
POST /api/v1/assets,PUT /api/v1/assets/{identifier},DELETE /api/v1/assets/{identifier}POST /api/v1/assets/{identifier}/identifiers,DELETE /api/v1/assets/{identifier}/identifiers/{identifierId}POST /api/v1/locations,PUT /api/v1/locations/{identifier},DELETE /api/v1/locations/{identifier}POST /api/v1/locations/{identifier}/identifiers,DELETE /api/v1/locations/{identifier}/identifiers/{identifierId}POST /api/v1/inventory/save— bulk scan ingest
- Shared response envelope — list responses return
{ "data": [...], "limit", "offset", "total_count" }; single-resource responses return{ "data": {...} }. See Pagination, filtering, sorting. - Shared error envelope —
{ "error": { "type", "title", "status", "detail", "instance", "request_id" } }on every non-2xx response, plusfields[]onvalidation_error. Field names are modeled on RFC 7807 but the envelope is JSON-wrapped, notapplication/problem+json. See Errors. - Per-key rate limiting — token bucket, default 60/min steady-state with 120-burst, surfaced via
X-RateLimit-Limit/X-RateLimit-Remaining/X-RateLimit-Reseton every response andRetry-Afteron 429. See Rate limits. - Request IDs — every response includes
X-Request-ID(ULID). InboundX-Request-IDis echoed back for client-supplied correlation IDs. - Interactive reference — the OpenAPI 3.0 spec is generated from the Go handlers and rendered at
/api(Redoc). Raw spec available at/api/openapi.jsonand/api/openapi.yaml. - Postman collection — regenerated alongside the spec; see Postman collection.
Fixed
POST /api/v1/locationsnow returns409 conflict(not500 internal_error) on duplicate identifiers, matching the behavior ofPOST /api/v1/assets.403 forbiddenis used (instead of400 bad_request) when a valid key attempts to access a resource in a different organization.- Write endpoints use
{identifier}path parameters consistently with read endpoints.
Notes
- No webhooks in v1. Outbound webhook delivery is planned for a future release; see Webhooks for the current placeholder page.
- No language SDKs in v1. Use the Postman collection or generate a client from the OpenAPI spec with your preferred codegen tool.
- Idempotency keys are not supported. Retry safety comes from HTTP semantics and unique-identifier constraints; see Errors → Idempotency.