Skip to main content

Customer share link returns not found

Orbit hands your end customers signed, self-serve links on several public surfaces:
  • Callback tracking links (GET|POST /api/v1/public/callbacks/:token/*) let a caller read status, cancel, or reschedule a queued callback without an account.
  • Help-center articles and the ticket portal (/public/help/*?org=<slug>) serve your published knowledge base and ticket status to visitors.
  • Community and idea boards (/public/community/*, /public/ideas/*?org=<slug>) expose your tenant’s public boards.
When a customer opens one of these links and it says not found, the person who can actually fix it is you, the operator, usually forwarding a customer complaint. This runbook decodes the family: CALLBACK_NOT_FOUND, ORG_NOT_FOUND, ARTICLE_NOT_FOUND, TICKET_NOT_FOUND, COMMUNITY_NOT_FOUND, and IDEAS_NOT_FOUND.

The shared 404 semantics

Every surface above collapses three different causes into the same 404 by design:
  1. Unknown or expired token or slug. The identifier never existed, was copied wrong, or aged out.
  2. Unpublished or expired resource. The record exists in your tenant but is draft, unpublished, or no longer public.
  3. Disabled surface. Your organization is not ACTIVE, or the surface’s feature toggle is off for your workspace.
The public endpoint deliberately returns one outcome for all three. It must not tell a stranger whether a resource exists, what state it is in, or whether a tenant is enabled, so the 404 itself is not an oracle and no amount of retrying splits the causes. Triage instead happens per surface, against your authenticated tenant controls. The short-link sibling of this family is covered separately in Short link not resolving or LINK_NOT_FOUND.

Per-surface ladders

The token in a callback link is a signed grant that embeds the callback id and your tenant. Work the ladder:
  1. Copy damage. The URL was retyped or truncated while forwarding. Copy the exact link from the original dispatch notification or SMS; tokens are opaque and case-sensitive.
  2. Expired token. Callback links live a week. A link older than that returns the same 404; re-issue the link server-side if the callback still needs customer action.
  3. Row gone. A callback that completed or was purged no longer resolves. Read the callback by the id your server stored at creation to confirm its outcome.
  4. Already canceled is not this error. A re-tap of cancel on a canceled callback acknowledges already canceled as a success, not a 404. A customer who sees not found holds a token that does not resolve; the callback was not canceled through that link.

Help center and ticket portal: ORG_NOT_FOUND, ARTICLE_NOT_FOUND, TICKET_NOT_FOUND

  • ORG_NOT_FOUND: the ?org= slug matches no ACTIVE organization. Pass the workspace slug, not the display name; a suspended org also collapses here.
  • ARTICLE_NOT_FOUND: the article is unknown to the portal, no longer ready (published), not flagged public, or its category is not public. All four render the same 404, so an article you unpublished an hour ago 404s for every visitor immediately.
  • TICKET_NOT_FOUND: the ticket-status portal could not authorise and resolve the ticket from the id and token pair in the link; a forwarded or truncated link loses that pairing.

Community and ideas boards: COMMUNITY_NOT_FOUND, IDEAS_NOT_FOUND

Unknown org and a disabled feature toggle collapse into the same 404. Confirm the workspace slug is ACTIVE, then confirm the community or ideas feature is enabled for your tenant. Re-enabling the toggle restores the same URL; nothing needs re-issuing.
  1. Name the surface from the URL. /api/v1/public/callbacks/<token> is a callback; /public/help/articles/<slug> or /help?org= is the help center; /public/community or /public/ideas is a board.
  2. Check your tenant state in the authenticated console: organization ACTIVE, and the surface’s feature enabled.
  3. Check the resource state: the callback id you stored still exists and is not terminal; the article is ready, flagged public, in a public category; the ticket exists.
  4. If state is good, the link copy is bad. Retrieve the exact URL from the original delivery and verify once with a single GET. Do not retype tokens or slugs.
  5. Re-issue server-side when the grant is gone. Create or refresh the resource through your authenticated API and mint a fresh signed link; replace it everywhere it was shared. Never extend a token client-side.
  6. Tell the customer which case they were in (expired, unpublished, disabled) after you have read the state; do not ask them to retry to find out.

Forged tokens: the 403 vs 404 split, and never retry

The token is an HMAC-signed payload, and any tamper fails a constant-time compare. Read surfaces report a forged token as the same 404 as an expired one, because distinguishing them would hand strangers an oracle; some mutation submits answer 403 instead. Either outcome is terminal for that token:
  • Do not retry a 404 or a 403 on a signed surface. The state cannot change underneath the request.
  • Do not probe tokens or slugs to enumerate resources. Scoping is per-link; probing only adds load and can trip the public rate limits.
  • A burst of 404s on tokens you never issued is expected noise on a public surface and is not, by itself, a defect to report.

What not to do

  • Do not retry the customer’s link in a loop to “see if it comes back”. Deterministic lookup misses do not.
  • Do not treat already canceled or already submitted acknowledgements as errors. They are success responses.
  • Do not publish and unpublish an article to probe its state. Read the state in the authenticated console instead.
  • Do not paste API keys or internal ids into the public link or the customer reply.

When to contact support

Contact support when your authenticated records show an ACTIVE org, an enabled surface, and a published, public resource, and a single verified copy of the link still 404s. Include the surface, the tenant-visible resource id (callback id, article slug, or ticket id), the response’s meta.request_id, and the approximate time of the request. Do not include the signed token itself; it is a bearer grant.