Problem-details shape
{
"title": "Forbidden",
"code": "trackable_access_code_required",
"detail": "Sign in, keep this trackable active on this browser, or provide this trackable's secret code or QR access code before posting comments or location reports.",
"status": 403
}
Not every trackable-related failure is a problem-details payload. Code lookup misses still return an ordinary success payload with { "found": false } so the caller can keep the lookup UI simple.
Error codes
| Code | Status | Typical route | Meaning | Client guidance |
|---|---|---|---|---|
trackable_not_found |
404 | Activate, group management, delete routes | The target trackable does not exist or cannot be resolved in that operation. | Refresh the list, re-run lookup, or confirm the GUID. |
trackable_comment_not_found |
404 | Comment update or delete | The target trackable comment no longer exists on that trackable. | Refresh comments and remove the stale UI entry. |
trackable_journey_stop_not_found |
404 | Journey-stop delete | The requested journey stop no longer exists on that trackable. | Refresh the journey and drop the stale action affordance. |
trackable_already_activated |
400 | POST /api/trackables/{trackableId}/activate |
The caller tried to activate a trackable that already has an owner scope. | Load the current details page instead of repeating activation. |
trackable_activation_required |
400 | Anonymous or signed-in comment/journey-stop writes | The item is still unactivated, so it cannot accept new comments or route activity yet. | Prompt an eligible signed-in owner to activate the trackable first. |
trackable_access_code_required |
403 | Anonymous comments and journey-stop writes | The caller is not signed in and also does not have an active browser session or another valid secret-backed access credential for that trackable. | Ask for the exact short secret code or QR token, keep the trackable active on this browser, or offer sign-in. |
trackable_access_code_invalid |
403 | Anonymous comments and journey-stop writes | The supplied access credential does not resolve to this specific trackable. | Tell the caller the code belongs to another item or was entered incorrectly. |
trackable_group_detach_forbidden |
403 | DELETE /api/trackables/{trackableId}/group |
The caller is not the original activator or an eligible group admin for the current group context. | Use a user who currently controls that grouped item. |
trackable_group_attach_forbidden |
403 | POST /api/trackables/{trackableId}/group |
The caller is not allowed to associate that detached trackable with a different group. | Return to the original activator or an allowed control context. |
trackable_comment_edit_forbidden |
403 | PUT /api/trackables/{trackableId}/comments/{commentId} |
Only the signed-in author of an authenticated comment can edit it. | Hide edit controls for everyone else. |
trackable_comment_delete_forbidden |
403 | Comment delete | The caller is neither the signed-in comment author nor an owner/team admin with moderation power. | Keep delete as a management-only action. |
trackable_journey_stop_delete_forbidden |
403 | Journey-stop delete | The caller is neither the authenticated author of that stop nor an owner/team admin. | Only show stop deletion when the current user can actually moderate it. |
trackable_journey_stop_convert_forbidden |
403 | Website conversion flow | Only the signed-in person who created an authenticated direct report can convert it into a note. | Do not show convert actions for anonymous or third-party-authored stops. |
trackable_journey_stop_convert_rejected |
400 | Website conversion flow | The stop exists, but the requested note conversion is not valid for that stop or note combination. | Ask the user to create a new note from the selected location instead. |
trackable_request_rejected |
400 or 403 | Fallback | A trackable rule rejected the request, but no more specific machine code was assigned. | Use the human-readable detail text and route context together. |
Place, history, and access stay separate: the journey stop preserves the snapped coordinate, the note keeps its own editable record, and the note's visibility plus required access scope decides who can open note content.
Journey reads expose the saved stop plus currentNotesAtCoordinate. That collection is today's visible note read model for the same coordinate, not proof that the stop permanently owns one note.
Lookup misses are not problem-details
{
"found": false,
"error": "Code not found."
}
The lookup API intentionally uses a success payload here because typing mistakes are expected and the UI usually wants to stay in lookup mode instead of switching into error handling.
When the code clearly belongs to another live system or should use the bring-your-own flow, the lookup payload can also include a help link that points to the origin site or the single-trackable create page.