Skip to main content
POST
Reject an edge proposal
Ownership is checked exactly as accept (both endpoints owned by the effective subject) — a foreign or unknown id returns 404 proposal_not_found. The proposal row is deleted (the same consumption accept performs, minus the edge write), so it leaves the queue immediately. REJECTION LEARNING (durable). The same transaction writes the pair — source node, target node, edge type, for this subject — into the proposal_rejections ledger, and the daemon’s GraphService.regenerate_all_proposals excludes rejected pairs (matched in both directions) from every later pass. So a rejected suggestion does not come back on the next sleep cycle, and the exclusion survives a re-embed: the ledger keys on node identity, not on the daemon’s embedding-SHA edge id. Re-rejecting is idempotent (the first verdict’s timestamp and actor stand), and accepting the pair later clears the record. rejectionRecorded in the response reports whether that write happened. It is false only on a deployment whose tenant schema predates the ledger (scripts/migrate_public_api_tables.py not yet run): there the reject still consumes the proposal and still writes its audit row, but the pair may be re-proposed, exactly as before this feature existed.

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.

Notes

  • Rejection is a teaching signal. rejectionRecorded says whether it was durably stored for the daemon to learn from.

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