Developer guide

Build Aurora clients that stay correct under retries, ambiguity, queue handoffs, and agent loops.

Guidance for retries, workspace changes, queue handoffs, durable comments, and long-lived Aurora clients.

Covers

Retries, caching, structured errors, queue handoffs, and long-lived client behavior.

Operating model

Aurora's contract model

Aurora's external API is not just a set of CRUD routes. It is a workspace-scoped execution surface for people and automation, which means identity resolution, queue semantics, and comment trails matter just as much as request syntax.

Discovery before mutation

Read workspace structure first so later writes can use valid teams, users, statuses, and queue identities.

Use stable natural keys

Prefer teamKey, projectKey, issueKey, and statusKey whenever your client can avoid opaque ids.

Make create flows idempotent

Use Idempotency-Key headers so retries do not fork records when workers, webhooks, or agents repeat work.

Recover from machine codes

Branch on code and details instead of parsing human text when references are stale or invalid.

Client architecture

Discovery and caching

Treat discovery as a lightweight schema sync for the current token workspace. It should happen before mutation and then refresh only when the surrounding workspace configuration actually changes.

EndpointWhat to cacheRefresh guidance
GET /api/externalToken queue identity, workspace metadata, endpoint map, capability flagsPer token workspace session
GET /api/external/teamsteamId and teamKey pairsRefresh on team-management changes
GET /api/external/usersownerId, reporterId, assigneeId, automationAgentsRefresh on membership or token-name changes
GET /api/external/statusesValid statuses for a teamRefresh when moving across teams or after status configuration changes

Practical caching rule

Cache by token workspace, not globally. Two Aurora tokens from the same user can still see different workspaces, teams, statuses, and automation queues.

Identity and lookup

Prefer keys first, ids second

The docs, the API, and the plugin all work best when clients speak in team keys, project keys, and issue keys wherever they can.

Prefer these inputs

These are easier for operators to reason about and easier for agent prompts to generate correctly.

  • teamKey over teamId when humans already know the team key
  • projectKey plus teamKey over projectId when building prompts or task plans
  • issueKey over issueId when the issue was referenced in chat or copied from the UI
  • statusKey over statusId when a team's workflow keys are already known

Use ids when

Opaque ids are still correct when they come from a trusted previous read or when disambiguation is required.

  • The client already persisted the id from a previous Aurora response
  • A project key is ambiguous without a team id or team key
  • You are patching the exact record you just fetched by id
  • Your workflow stores canonical Aurora ids internally for subsequent calls

Create flows

Retry safety with Idempotency-Key

The fastest way to create duplicate projects or issues is to let a worker or agent retry a create call without a stable key. Aurora's create routes are designed so you do not have to.

Recommended idempotent project create
curl -X POST https://www.auroraworkos.com/api/external/projects \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: source-system:project:weekly-scorecard" \
  -d '{
    "name": "Weekly Scorecard"
  }'

Key design rule

Use a key shape derived from your upstream system and entity id, such as source-system:entity-type:external-id. That makes retries deterministic across restarts, not just within one process lifetime.

Large collections

Cursor pagination

When you are reading lists for sync, triage, or queue pickup, do not assume one page is enough. Aurora's list routes expose a cursor model that is intentionally simple to integrate.

RouteSupportsTypical use
GET /api/external/projectslimit, cursorWorkspace and team-scoped project inventory
GET /api/external/issueslimit, cursorIssue triage, backlog review, automation pickup
GET /api/external/meetingslimit, cursorMeeting history and workflow state review
Issue pagination pattern
GET /api/external/issues?limit=50

{
  "issues": [...],
  "pageInfo": {
    "hasMore": true,
    "nextCursor": "opaque-cursor",
    "limit": 50
  }
}

Error recovery

Structured errors are part of the contract

The Aurora API returns machine-usable errors so clients and agents can choose a recovery path without scraping human prose.

Error response shape
{
  "error": "Human-readable message",
  "code": "MACHINE_CODE",
  "details": {
    "field": "value"
  },
  "suggestion": "Recovery guidance for a client or agent."
}
CodeMeaningRecommended recovery
UNAUTHORIZEDThe request did not include a valid, active API token or OAuth access token.Refresh credentials and retry after confirming you are calling /api/external or /api/mcp with the right auth method.
TEAM_NOT_FOUNDThe supplied teamId or teamKey could not be resolved inside the token workspace.Refresh team discovery and retry with a valid teamId or teamKey.
NO_TEAM_AVAILABLEA create request needed a default team but the workspace has no usable team.Create or restore a workspace team, then retry the request with teamId or teamKey.
PROJECT_KEY_AMBIGUOUSA projectKey was supplied without enough team context to resolve it uniquely.Add teamKey or switch to projectId.
PROJECT_NOT_FOUNDThe requested project could not be found or is outside the caller's workspace/project access boundary.Refresh project discovery, confirm project access, and retry with a valid projectId or teamKey/projectKey pair.
PROJECT_TEAM_MISMATCHThe resolved project does not belong to the supplied team context.Use the project's actual teamKey/teamId or switch to projectId-only lookup.
PROJECT_KEY_CONFLICTThe requested project key is already used in the target team.Choose a unique project key or update the existing project instead.
NAME_REQUIREDA project, external owner preset, or agenda status write was sent without a required name.Validate payloads before write calls and retry with a non-empty name.
TEAM_CHANGE_BLOCKEDA project team move was requested while the project still has issues.Move or resolve project issues first, or leave the project on its current team.
ISSUE_NOT_FOUNDThe requested issue could not be found or is outside the caller's workspace/project access boundary.Refresh issue lookup with GET /api/external/issues or GET /api/external/issues/by-key/{issueKey}.
PROJECT_REQUIREDAn issue or agenda action requires a target project but none was supplied or resolved.Provide projectId or projectKey with team context when needed.
TITLE_REQUIREDAn issue create request was sent without a non-empty title.Validate issue payloads before write calls and retry with title.
STATUS_INVALID_FOR_PROJECTThe chosen status does not belong to the issue's project team.Reload statuses for the target team and retry with a valid statusId or statusKey.
STATUS_INVALID_FOR_PROJECT_WORKFLOWThe chosen status is hidden or disallowed by the project's workflow settings.Reload project workflow or board data and choose a visible, allowed status.
STATUS_NOT_FOUNDThe supplied statusId or statusKey could not be resolved.Refresh statuses for the target team and retry with a current status reference.
WORKFLOW_TRANSITION_BLOCKEDThe requested status move is blocked by project workflow transition rules.Move through an allowed transition path or adjust the project workflow first.
MEETING_NOT_FOUNDThe requested meeting could not be found in the caller's accessible workspace/projects.Refresh meeting discovery and confirm the token has project access when the meeting is project-linked.
MEETING_TITLE_REQUIREDA meeting create or update request was sent without a non-empty title.Provide title before retrying the meeting write.
INVALID_MEETING_TIMEMeeting or agenda dates/times were malformed or inconsistent.Use ISO datetimes for startsAt/endsAt and YYYY-MM-DD for agenda dates, with end after start.
RECURRENCE_START_REQUIREDA recurring meeting was requested without a usable start date.Provide startsAt when recurrenceType is not none.
AGENDA_ITEM_NOT_FOUNDThe requested agenda item could not be found inside the supplied meeting.Reload the meeting agenda and retry with a current agendaItemId.
AGENDA_ITEM_TITLE_REQUIREDAn agenda item create request was sent without a non-empty title.Provide title before retrying the agenda item write.
AGENDA_STATUS_NOT_FOUNDThe supplied agenda status id could not be resolved in the workspace.Reload meeting settings and retry with a current agenda status id.
AGENDA_STATUS_DELETE_BLOCKEDThe agenda status cannot be deleted because agenda items still reference it.Move agenda items to another status, then retry deletion.
OWNER_NOT_IN_WORKSPACEAn owner, reporter, actor, or token-backed user identity could not be resolved in the workspace.Refresh users, confirm the user is a workspace member, or recreate the API token from a current workspace member account.
OWNER_NOT_FOUNDAn agenda owner or external owner preset could not be found.Reload agenda owners or meeting settings before retrying.
OWNER_REQUIREDAn agenda owner write did not include an internal user or external owner value.Provide userId, presetId, externalName, or externalEmail.
ASSIGNEE_NOT_IN_WORKSPACEThe requested assignee is not a workspace member or active automation-agent id.Refresh users and retry with a valid human user id or api-token:<name> identity.
ASSIGNEE_NOT_IN_PROJECTThe requested assignee does not have access to the target project.Grant project access to the user or automation agent, or choose a different assignee.
ASSIGNEE_NOT_IN_PROJECT_TEAMThe requested human assignee is not a member of the target project team.Add the user to the project team or use an allowed automation-agent assignee.
ASSIGNEE_FILTER_CONFLICTThe request combined assignedToMe with an explicit assigneeId.Use either assignedToMe=true or assigneeId, not both.
REPORTER_NOT_IN_WORKSPACEThe requested reporter is not a workspace member.Refresh users and retry with a workspace member user id.
COMMENT_BODY_REQUIREDA comment create request was sent without a non-empty body.Validate comment payloads before write calls and retry with a non-empty string body.
COMMENT_PARENT_NOT_FOUNDA threaded reply referenced a parent comment that does not belong to the issue.Reload issue comments and retry with a current parentCommentId.
INVALID_TARGET_TYPEA meeting work-link request used an unsupported targetType.Use issue, project, discussion_topic, or agenda_item.
TARGET_REQUIREDA meeting work-link request omitted both targetId and targetKey.Provide targetId, or targetKey for supported issue/project targets.
UNSUPPORTED_ACTIONThe request attempted a guarded operation such as converting without an issue action or sending an empty update.Read the response suggestion/details, adjust the payload, and retry through the supported route.

Queues and orchestration

Automation queues and visible execution

Aurora treats API token names as first-class queue identities. That makes assignment, polling, and durable comment trails predictable for both background workers and visible chat-driven flows.

Recommended automation pattern

Use tokens as queue identities, not as a hidden replacement for human ownership.

  • Use GET /api/external first to discover token.assigneeId and capability flags before queue polling.
  • Treat the API token name as the queue identity for automation assignment and assignedToMe filtering.
  • Prefer visible chat-orchestrated execution for ambiguous work and reserve background workers for deterministic tasks.
  • Leave humans as reporterId, move issues through todo -> in-progress -> in-review, and always post a summary comment on completion.
Queue pickup query
curl "https://www.auroraworkos.com/api/external/issues?assignedToMe=true&statusKey=todo" \
  -H "Authorization: Bearer $TOKEN"

Agent setup

Bind Codex to an Aurora workspace

Use workspace settings to generate a secure connect command for the repo or worktree Codex should operate from. The command opens Aurora in the browser, creates a dedicated token, stores it in macOS Keychain, and writes the local project binding.

Secure connect command shape
sh plugins/aurora-api/scripts/bind-project.sh connect \
  --base-url https://www.auroraworkos.com \
  --workspace-id <workspace-id> \
  --token-name "Codex automation" \
  --execution-mode chat-orchestrated
Manual token fallback
export AURORA_PAT_WORKSPACE=aurora_pat_...

sh plugins/aurora-api/scripts/bind-project.sh bind-token \
  --base-url https://www.auroraworkos.com \
  --token-env-var AURORA_PAT_WORKSPACE \
  --project <binding-id> \
  --execution-mode chat-orchestrated

Multiple local bindings

Aurora stores repo and worktree bindings in ~/.codex/aurora-projects.json. Cwd-based resolution picks the most specific matching projectPath, and --project can select a binding explicitly for polling or staged handoff commands.

Recipes

Workflow recipes

These patterns are the shortest path to reliable real-world Aurora integrations.

Fresh workspace bootstrap
1. GET /api/external
2. GET /api/external/teams
3. GET /api/external/users
4. GET /api/external/statuses
5. POST /api/external/projects
6. POST /api/external/issues
Comment and status update loop
1. GET /api/external/issues/by-key/PE-001
2. POST /api/external/issues/{issueId}/comments
3. PATCH /api/external/issues/{issueId}
4. Re-read the issue if the next step depends on the new status or assignee
Meeting agenda to issue
1. GET /api/external/meetings/settings
2. GET /api/external/meetings/{meetingId}/agenda-items
3. POST /api/external/meetings/{meetingId}/agenda-items/{agendaItemId}/convert
4. POST /api/external/meetings/{meetingId}/agenda-items/{agendaItemId}/notes/publish
5. POST /api/external/issues/{issueId}/comments (optional summary or handoff note)

Human-friendly companion pages

If you need the endpoint list while following one of these recipes, keep the API reference open beside this guide.

Know the boundaries

Current constraints

These are the constraints clients should plan around today instead of discovering them after they ship.

ConstraintWhat it means
One workspace per tokenA token cannot traverse workspaces. Resolve everything within its workspace boundary.
No token scopes yetA valid token can use all supported external routes for its workspace.
External routes onlyTokens and connector access work on /api/external/* and /api/mcp, not internal app pages.
OAuth connector callers differ from PAT callersConnector calls run as the approving human user; PAT calls run as the token queue identity.
Files and attachments are internal todayFile repository APIs plus issue and meeting attachment routes require normal app-session auth; PAT external file routes are not exposed yet.
Child background workers may need broader sandboxingIf a hidden Codex child must call Aurora or other external services, workspace-write may not be enough.