---
title: "Accept Suggestions"
method: POST
path: "/extensions/roboledger/{graph_id}/operations/accept-suggestions"
tags: ["RoboLedger: Ledger & Events"]
---

# Accept Suggestions

`POST /extensions/roboledger/{graph_id}/operations/accept-suggestions`

## Request

- Base URL: `https://api.robosystems.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.robosystems.ai/extensions/roboledger/{graph_id}/operations/accept-suggestions`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Take the suggestion on every open bank line the filters select, oldest first: each is classified to its `suggested_element_id` through the same update a single line goes through, and posted too with `commit: true`. Select by `source`, `agent_id`, `suggestion_source` (`agent_default` for the learned ones), a date range, or explicit `event_ids` from a multi-select. A line it cannot take — no suggestion to take, already classified or posted, a closed month, a choice the handler refuses — comes back `skipped` with the reason, never forced. `dry_run: true` reports the counts without writing; `limit` bounds a call and `truncated` says more matched.

**Idempotency**: supply an `Idempotency-Key` header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict.

## Path parameters

- `graph_id` string, required

## Headers

- `Idempotency-Key` string, nullable

## Request body

- AcceptSuggestionsRequest: Take the suggestion on every open bank line the filters select.
  - `entity_id` string, nullable: The entity whose inbox to act on. Omit for the group parent.
  - `event_ids` string[], nullable: Explicit lines, as from the inbox's multi-select; each is answered, even one that cannot be taken. The other filters still narrow them.
  - `source` string, nullable: Only lines from this feed (`plaid`, `mercury`).
  - `agent_id` string, nullable: Only one counterparty's lines.
  - `suggestion_source` string, nullable: Only lines whose suggestion came from here: `agent_default` (the counterparty's learned default), `tier0` (the bank's category) or `ai`.
  - `occurred_from` string, date, nullable: Only lines dated on or after this day.
  - `occurred_to` string, date, nullable: Only lines dated on or before this day.
  - `commit` boolean: Post each taken line as well (captured → committed). Off, the lines are classified and wait for a person to post them.
  - `limit` integer: At most this many lines per call, oldest first; `truncated` in the response says whether more matched.
  - `dry_run` boolean: Report what each line would do without writing. A closed month is found only when a line actually posts, so a real run can still skip one a dry run counted.

## Response `200`

Successful Response

- OperationEnvelopeAcceptSuggestionsResponse
  - `operation` string, required: Kebab-case operation name
  - `operationId` string, required: op_-prefixed ULID for audit and SSE correlation
  - `status` 'completed' | 'pending' | 'failed', required: Operation lifecycle state
  - `result` AcceptSuggestionsResponse: The batch's counts, and every line it looked at.
    - `selected` integer, required: Lines the filters matched, before the limit.
    - `classified` integer, required: Lines classified to their suggestion and left to post.
    - `committed` integer, required: Lines classified to their suggestion and posted.
    - `skipped` integer, required: Lines not taken, each with a reason.
    - `truncated` boolean, required: More lines matched than the limit allowed in this call.
    - `dry_run` boolean, required: Nothing was written.
    - `lines` AcceptSuggestionLine[], required: Each line looked at, oldest first.
      - `event_id` string, required: The line.
      - `outcome` 'classified' | 'committed' | 'skipped', required: What happened to it.
      - `reason` string, nullable: Why a skipped line was not taken: `not_open` (already classified, posted or retracted), `no_suggestion` (nothing to take, or a name that matches no account), `source_changed` (the feed changed it after capture), `suggestion_changed` (a line taken earlier in the batch moved the counterparty's default, so this one's suggestion is not the one selected; review it again), `closed_period`, `locked` (another process holds it; retry), or `refused` (the handler would not post the choice).
      - `detail` string, nullable: The refusal's own words, when there was one.
      - `element_id` string, nullable: The account the suggestion names.
      - `description` string, nullable: The line's description.
  - `at` string, required: ISO-8601 UTC timestamp
  - `createdBy` string, nullable: User ID that initiated the operation
  - `idempotentReplay` boolean: True when this envelope came from the idempotency cache — the underlying command did not execute again. False on fresh executions.

## Other responses

- `400`: Invalid request
- `401`: Authentication required
- `403`: Access denied
- `404`: Resource not found
- `409`: Idempotency-Key conflict — key reused with different body
- `422`: Validation error
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/robosystems/apis/robosystems-api.md) · [All operations](https://skmtc.dev/robosystems/apis/robosystems-api/llms.txt) · [OpenAPI document](https://skmtc.dev/robosystems/apis/robosystems-api/revisions/e661e2d5ca6a?raw)
