View Markdown ↗CONTRACT 0.1.0
On this page

Guarded browser HTTP reference

Scope and authentication

This is the implemented same-origin browser contract, not an agent REST credential option. The controlled application origin is https://app.agentcodex.io. Current real Passport sign-in and authenticated notebook operation remain unverified end to end. Remote agent clients should use a future authorized MCP integration, not extract or replay browser cookies.

Machine schemas: OpenAPI 3.1. Its server origin is the dashboard, and operation paths already include their full route. There is no /v1 prefix. Do not prepend one. Documentation and machine files are static assets on the public website; API calls belong to the dashboard origin.

Browser authentication uses the HttpOnly __session cookie under Firebase Hosting. All entry operations, including GET, require X-Field-Notes-Csrf matching the current session. Mutations require exact Origin https://app.agentcodex.io. An Origin header, when present on a read, must also match. No CORS or API-key/Bearer login is supported by these routes.

Health

GET /health (also HEAD) returns {"service":"field-notes","status":"browser-auth-configured"} for a browser-configured runtime. The service name is a stable compatibility identifier. It reports construction, not successful authentication, database readiness or remote MCP availability. Other methods receive 405 with Allow: GET, HEAD.

Browser sign-in routes

Use the dashboard's flow. These are protocol descriptions, not permission to automate owner confirmation.

  • POST /auth/passport/begin, body {}: begins a browser-bound challenge and sets its HttpOnly cookie. Returns clientId, nonce, signInFingerprint and expiresAt in epoch milliseconds.
  • POST /auth/passport/callback, body {token, nonce}: approved server-to-server Passport delivery, not a browser login form. Returns message and confirmationCode, both containing the one-time code, plus its actual expiresAt in epoch milliseconds. The message remains the code for Passport's existing siteMessage contract. This route is handled before browser Origin checks. Never paste the assertion into chat or reuse it as a notebook bearer.
  • POST /auth/passport/status, body {nonce} with the original challenge cookie: returns {status:"pending", expiresAt} or {status:"arrived", issuer, passportId, expiresAt} and records that the identity was shown. This is the stored challenge deadline, which can shorten after arrival and never renews on a status check. It does not issue a session.
  • POST /auth/passport/confirm, body {nonce, confirmationCode, expectedPassportId} with the original challenge cookie: checks the displayed exact identity and one-time code. Returns {status:"authenticated", issuer, passportId, expiresAt, csrfToken} and sets the session cookie. The response never exposes the session token.
  • POST /auth/passport/cancel, body {nonce} with the original challenge cookie: cancels that challenge and clears the cookie; returns {cancelled:true}.
  • GET /auth/session: no cookie returns {status:"anonymous"}; a valid cookie returns {status:"authenticated", issuer, passportId, expiresAt, csrfToken}. A syntactically valid cookie whose token is unknown, revoked or expired returns 401. A malformed, duplicate or oversized cookie is treated as absent by this route.
  • POST /auth/logout, body {} with session cookie and CSRF: revokes the current browser session, clears the cookie, returns {signedOut:true, scope:"current-session"}.
  • POST /auth/logout-all, body {} with session cookie and CSRF: revokes all current browser sessions for the exact identity, clears the cookie, returns {signedOut:true, scope:"all-current-sessions"}.

All mutation bodies above are strict JSON objects with no extra fields. Challenge begin/callback are rate-limited. Begin/status/confirm/cancel are challenge operations, not CSRF-authenticated notebook calls. Callback JSON has a 20 KiB body cap; the other browser JSON routes have a 512 KiB parser cap. Per-field limits still apply.

Entry routes

These require the matching authenticated browser cookie and CSRF header. The server derives ownership. Never send owner, issuer, passportId or agentId as an ownership override.

  • POST /entries: body {requestId, entry}. Returns HTTP 201 and {entry}. Same save contract and retry semantics as field_notes_save.
  • GET /entries/{id}: returns HTTP 200 and {entry}. Same retrieval contract as field_notes_get.
  • PUT /entries/{id}: body {expectedRevision, entry}. Returns HTTP 200 and {entry}. Full replacement with revision checks, not PATCH.
  • POST /entries/search: body {query?, tag?, relatedAgentId?, limit?, cursor?}. Returns HTTP 200 and {entries, nextCursor?, coverage}. Empty object browses. This is not GET /entries or a URL query search.

See data and limits, MCP tool reference and errors for exact shared behavior. Error responses do not disclose whether a missing ID belongs to another codex. Private route responses carry Cache-Control: no-store; do not cache or log private bodies or credentials.

Closed remote boundaries

The default function responds 501 at /mcp because remote OAuth is not configured. The current website/dashboard Hosting rewrites do not publish that path or OAuth metadata. Do not infer a canonical MCP resource, auth-server metadata URL, authorize/token route or client registration endpoint from candidate source. These docs intentionally do not present those as working public operations.