Skip to main content
POST
Accept an edge proposal
Writes the edge exactly as the dashboard accept does — the proposal moves into graph_edges (edge_id = proposal_id, is_approved = TRUE, all cross-domain fields preserved) and the proposal row is deleted, atomically in one transaction. The edge carries created_by = api:<caller> for audit. A proposal id that is not the subject’s (cross-org, cross-user, or already consumed) returns 404 proposal_not_found. Acceptance SUPERSEDES a prior rejection: any proposal_rejections row for this pair (either direction) is cleared in the same transaction, so a pair you once rejected and later accepted is not silently blocked from being re-suggested if the edge is removed again. Brain staleness is not stamped on brain_metadata: its status CHECK allows only none|queued|training|ready|failed (no stale) and writing it would also corrupt the in-flight-train guard. The new edge instead changes the org’s live graph_edges count, which the ExoBrain compares against its exported N/E on every query — so /v1/retrieve honestly flips to degradationReason="brain_stale" on the next call, no metadata flag needed.

Authorization

This route requires the write scope. A missing or invalid credential returns 401 authentication_error. A valid credential without the scope returns 403 permission_denied, and the problem body names the exact scope required.

Headers

These are request conventions the contract does not declare as parameters, so they do not appear in the schema tables below.

Success responses

Errors

Beyond the shared statuses, this route can answer with proposal_not_found, idempotency_in_flight, idempotency_key_reuse. Every problem body names its own code, and the type URI always resolves to the matching page. Every error is an RFC 9457 application/problem+json body carrying a stable code, a requestId, and a suggestedAction where Exo has one. See Errors.

Authorizations

X-Exo-API-Key
string
header
required

An Exo API key (exo_...) sent as the X-Exo-API-Key header.

Path Parameters

proposal_id
string
required

The proposal id from GET /v1/proposals.

Response

Successful Response

The outcome of an accept/reject on a proposal.

decision is accepted or rejected. edgeId is the id of the edge created by an accept (equal to the proposal id); null on reject.

rejectionRecorded reports whether the reject was written to the durable rejection ledger, i.e. whether this pair is now permanently excluded from re-suggestion rather than merely removed from the queue. It is null on accept (which has nothing to record) and false only on a deployment whose schema predates the ledger.

decision
string
required
proposalId
string
required
edgeId
string | null
rejectionRecorded
boolean | null