Documentation
DocsAPI reference

Review queue

The review queue is where approval requests wait for a person to approve or deny them. These endpoints list the queue, retrieve one request, claim it while you look at it, and record your decision.

Updated Sep 23, 2026

List the review queue

GET/api/v1/requestsSession or API keyRequires request.read

Returns the list of approval requests that reached human review: pending, decided by a person, or expired while waiting. Approval requests the pipeline decided automatically are not included. They stay in the audit log and can still be retrieved by id. Requests are returned newest first.

Pass agent_slug to list one agent's requests instead. That list includes the requests the pipeline decided automatically.

Request

Parameters

ParameterTypeDescription
limitquery · integer

How many requests to return. Defaults to 50, at most 200.

agent_slugquery · string

Show one agent's requests instead of the queue, including the ones the pipeline decided.

offsetquery · integer

Number of visible matching requests to skip before returning this page.

qquery · string

Case-insensitive literal substring of the tool or instance name.

statusquery · enum

Return only requests with this outcome.

One of pending, approved, denied, expired, cancelled
scopequery · enum

Which layer of the queue to return, from the caller's standpoint. notified is what the caller was told about: requests a notification addressed to them, or a colleague handed them. decidable is what the caller may decide outright: requests routed to them directly, through a team, or by being added, plus unrouted requests where any reviewer may take them. visible (the default) is everything the caller may see, whoever decides it. Each layer contains the one before it. Ignored for API keys, which have no membership.

One of notified, decidable, visible

Response

Response codes

StatusBodyDescription
200object

The requests, newest first

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

You cannot read requests

Response body200

Example

GET /api/v1/requests
curl -X GET "$WITHHUMAN_URL/api/v1/requests" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "requests": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "agent_slug": "support-agent",
      "agent_instance_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "agent_name": "support-agent",
      "agent_instance_name": "ci-runner-07",
      "tool": "issue_refund",
      "server": "stripe",
      "arguments": {
        "amount": 4900,
        "reason": "duplicate_charge"
      },
      "agent_reasoning": "Refunding the duplicate charge for [email protected].",
      "context": {
        "run_id": "4821",
        "framework": "claude-code"
      },
      "status": "approved",
      "deadline_at": "2026-09-09T12:00:00Z",
      "created_at": "2026-09-08T12:00:00Z",
      "decision": {
        "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "request_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "status": "approved",
        "note": "OK, but flag this account for review.",
        "channel": "web",
        "reviewer_display_name": "Chris",
        "reviewer_email": "[email protected]",
        "authentication": {
          "method": "local_password",
          "assurance": "strong",
          "authenticated_at": "2026-09-08T12:02:11Z",
          "session_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
          "credential_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        },
        "idempotency_key": "decision-7ab8c8ec",
        "decided_at": "2026-09-08T12:02:11Z"
      },
      "updated_at": "2026-09-08T12:05:00Z",
      "claim": {
        "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "display_name": "Chris",
        "claimed_at": "2026-09-08T12:01:30Z",
        "expires_at": "2026-09-08T12:16:30Z"
      },
      "presentation": {
        "source": "built_in",
        "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "title": "Edit {{/file_path}}",
        "fields": [
          {
            "path": "/body",
            "label": "Body",
            "kind": "text",
            "language": "python",
            "before": "/old_string",
            "after": "/new_string",
            "item": {},
            "role": "primary"
          }
        ]
      }
    }
  ]
}

Retrieve a request

GET/api/v1/requests/{id}Session or API keyRequires request.read

Returns one approval request. The response includes its current status, its decision once there is one, and any claim a reviewer holds on it. Pass wait to hold the response until the request is decided.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

waitquery · string

How long to hold the response for a decision, as a duration such as 30s. Capped at 30 seconds. Omit to return immediately.

Response

Response codes

StatusBodyDescription
200ApprovalRequest

The request in its current state

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

You cannot read requests

404ErrorResponse

No such request

Response body200

iduuidrequired
organization_iduuidrequired
agent_slugstringrequired

The slug of the agent that made the request.

agent_instance_iduuidrequired

The running copy of the agent that made the request.

agent_namestringrequired

The agent's name when the request was made.

agent_instance_namestringrequired

The instance's name when the request was made.

toolstringrequired

The tool the agent wants to call, as the server that defines it names it.

serverstring

The MCP server that defines the tool, as the adapter reported it. Absent for a runtime's built-in tools.

argumentsanyrequired

The exact arguments the tool will run with if approved.

The agent's own explanation, if it gave one.

Where the call comes from, as recorded by the adapter.

statusenumrequired

pending while waiting for a decision, then one of the four final states. cancelled means the requesting instance withdrew it; treat it as a denial.

One of pending, approved, denied, expired, cancelled

deadline_atdate-timerequired

When the request expires if nobody has decided: created_at plus the timeout.

created_atdate-timerequired

The outcome of an approval request and who produced it.

updated_atdate-timerequired

Moves on every change a reviewer should notice, escalation progress included, so a client refetches the review when it changes.

A reviewer's claim on a pending request: an advisory marker that they are looking at it. Absent once released, lapsed, or the request is no longer pending.

The presentation a request renders with and where it came from.

Example

GET /api/v1/requests/{id}
curl -X GET "$WITHHUMAN_URL/api/v1/requests/{id}?wait=30s" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "agent_slug": "support-agent",
  "agent_instance_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "agent_name": "support-agent",
  "agent_instance_name": "ci-runner-07",
  "tool": "issue_refund",
  "server": "stripe",
  "arguments": {
    "amount": 4900,
    "reason": "duplicate_charge"
  },
  "agent_reasoning": "Refunding the duplicate charge for [email protected].",
  "context": {
    "run_id": "4821",
    "framework": "claude-code"
  },
  "status": "approved",
  "deadline_at": "2026-09-09T12:00:00Z",
  "created_at": "2026-09-08T12:00:00Z",
  "decision": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "request_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "status": "approved",
    "note": "OK, but flag this account for review.",
    "channel": "web",
    "reviewer_display_name": "Chris",
    "reviewer_email": "[email protected]",
    "authentication": {
      "method": "local_password",
      "assurance": "strong",
      "authenticated_at": "2026-09-08T12:02:11Z",
      "session_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "credential_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
    },
    "idempotency_key": "decision-7ab8c8ec",
    "decided_at": "2026-09-08T12:02:11Z"
  },
  "updated_at": "2026-09-08T12:05:00Z",
  "claim": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "display_name": "Chris",
    "claimed_at": "2026-09-08T12:01:30Z",
    "expires_at": "2026-09-08T12:16:30Z"
  },
  "presentation": {
    "source": "built_in",
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "title": "Edit {{/file_path}}",
    "fields": [
      {
        "path": "/body",
        "label": "Body",
        "kind": "text",
        "language": "python",
        "before": "/old_string",
        "after": "/new_string",
        "item": {},
        "role": "primary"
      }
    ]
  }
}

Claim a request

POST/api/v1/requests/{id}/claimSession or API keyRequires request.claim

Marks a pending request as being looked at by you. Other reviewers see who has it, and its notifications pause. A claim is advisory: anyone allowed to decide the request can still decide it.

A claim lapses after the organization's claim timeout, 15 minutes by default. It also lapses at the request's deadline if that comes first. Claiming a request you already hold returns the same claim. You cannot claim a request another reviewer holds. Wait for their claim to lapse, or for them to release it.

Owners and reviewers can claim. If the request was routed to an escalation path, only the people on that path can claim it. Owners can always claim.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

Response

Response codes

StatusBodyDescription
200object

The claim you hold

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

You cannot claim this request. Your membership is inactive, you lack permission to decide, or the request was routed to other people

404ErrorResponse

No such request

409ErrorResponse

Another reviewer holds the claim, or the request is no longer pending

Response body200

claimClaimrequired

A reviewer's claim on a pending request: an advisory marker that they are looking at it. Absent once released, lapsed, or the request is no longer pending.

Example

POST /api/v1/requests/{id}/claim
curl -X POST "$WITHHUMAN_URL/api/v1/requests/{id}/claim" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "claim": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "display_name": "Chris",
    "claimed_at": "2026-09-08T12:01:30Z",
    "expires_at": "2026-09-08T12:16:30Z"
  }
}

Release a claim

DELETE/api/v1/requests/{id}/claimSession or API keyRequires request.claim

Releases your claim on a request. Other reviewers then see it as unclaimed. Only the reviewer holding a claim can release it. Other reviewers' claims lapse on their own.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

Response

Response codes

StatusBodyDescription
204

The claim is released

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Another reviewer holds the claim

404ErrorResponse

No live claim on this request

Example

DELETE /api/v1/requests/{id}/claim
curl -X DELETE "$WITHHUMAN_URL/api/v1/requests/{id}/claim" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"

Approve or deny a request

POST/api/v1/requests/{id}/decisionSession or API keyRequires request.decide

Records your decision on a pending request and returns once it is durably stored. The agent waiting on the request sees the decision on its next read.

Every call needs an Idempotency-Key header. Repeating a call with the same key returns the decision already recorded.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

Idempotency-Keyrequiredheader · string

A key of your choosing that identifies this call, so a retry does not act twice. See Idempotency in the API overview.

Request body

statusenumrequired

The decision.

One of approved, denied

notestring

A note for the agent. It is returned with the decision.

channelstring

Where the decision was made, recorded on the decision, for example web or slack. Defaults to web.

The reviewer's explicit acknowledgement that they are deciding outside the request's routing (break glass). Required, alongside request.decide.unrouted, when routing did not hand them the request; without it such a decision is refused with reason outside_routing_required. Part of the decision's intent under the idempotency key.

Response

Response codes

StatusBodyDescription
200DecisionOperation

The recorded decision

400ErrorResponse

The Idempotency-Key header is missing, or status is not approved or denied

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

You cannot decide this request. Your membership is inactive, you lack permission to decide, the request was routed to other people, or your sign-in is too old or not strong enough. A routing refusal carries RoutingRejectionDetails in error.details, whose reason is not_targeted, break_glass_only, or outside_routing_required.

404ErrorResponse

No such request

409ErrorResponse

The request already has a decision or has expired, or the idempotency key was already used with different parameters

Response body200

iduuidrequired

The operation's id. The decision itself has its own.

organization_iduuidrequired
request_iduuidrequired

The request that was decided.

statusenumrequired

applied once the decision is stored. A 200 response always says applied: the call waits for the outcome, and a rejected decision comes back as an error.

One of pending, applied, rejected

Why the decision was rejected. Set for rejected only.

The rejection in plain text. Set for rejected only.

The outcome of an approval request and who produced it.

created_atdate-timerequired
completed_atdate-time

When the decision was stored.

Example

POST /api/v1/requests/{id}/decision
curl -X POST "$WITHHUMAN_URL/api/v1/requests/{id}/decision" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Idempotency-Key: 4f1c9a2e-7b3d-4e8f-a1c5-2d6b8e0f9a31" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "approved",
  "note": "OK, but flag this account for review.",
  "channel": "web",
  "outside_routing": true
}'
200 response
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "request_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "status": "applied",
  "error_code": "string",
  "error_message": "string",
  "decision": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "request_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "status": "approved",
    "note": "OK, but flag this account for review.",
    "channel": "web",
    "reviewer_display_name": "Chris",
    "reviewer_email": "[email protected]",
    "authentication": {
      "method": "local_password",
      "assurance": "strong",
      "authenticated_at": "2026-09-08T12:02:11Z",
      "session_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "credential_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
    },
    "idempotency_key": "decision-7ab8c8ec",
    "decided_at": "2026-09-08T12:02:11Z"
  },
  "created_at": "2026-09-08T12:02:11Z",
  "completed_at": "2026-09-08T12:02:11Z"
}

Retrieve a request's routing

GET/api/v1/requests/{id}/routingSession or API keyRequires request.read

Returns who was asked to review a request when it entered human review. If an escalation path took the request, the people on that path were notified, and only they can decide it. If no path applied, every reviewer who can decide was notified, and any of them can decide it. Routing is fixed when the request enters human review. Later changes to pipelines or paths do not move it.

Requests the pipeline decided automatically never entered human review and have no routing.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

Response

Response codes

StatusBodyDescription
200ApprovalRouting

Where the request was routed

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

You cannot read requests

404ErrorResponse

No such request, or it never reached human review

Response body200

outcomeenumrequired

escalated when an escalation path took the request. default_queue when no path applied and every reviewer who can decide was asked.

One of escalated, default_queue

reasonenumrequired

How the outcome came about. block_escalation: the pipeline block that asked for a person named the path. pipeline_default: the pipeline's default path took it. no_escalation: the pipeline named no path. path_inactive: the named path had no active revision. evaluation_error: the path could not be resolved. The last three mean no path applied.

One of block_escalation, pipeline_default, no_escalation, path_inactive, evaluation_error

urgencyenumrequired

The urgency the request was routed with. Always standard today.

One of standard, interrupt

The path that took the request. Present for escalated only.

The name of the path revision that took the request. Present for escalated only.

The path revision that was active at the time. Present for escalated only.

The pipeline revision that routed the request. Present for escalated only.

The pipeline block that named the path. Present for block_escalation only.

The people and teams the pinned path reaches for this request, in path order: the levels whose request conditions hold for it, plus both branches of any working-hours or urgency test, at every level regardless of timing. Only these people, and added_reviewers, may claim or decide. Empty for default_queue. Empty for escalated means the path reaches nobody for this request and only a break-glass reviewer may decide it.

People added to the request's routing after the snapshot was pinned, oldest first.

The team escalation policy revisions pinned beside the path, one per team the path reaches for this request that had an active policy at routing time. A team absent here is notified all at once when a level reaches it. Empty for default_queue.

The escalation executor's current position. Null before its first tick and for default_queue.

created_atdate-timerequired

When the request entered human review.

Example

GET /api/v1/requests/{id}/routing
curl -X GET "$WITHHUMAN_URL/api/v1/requests/{id}/routing" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "outcome": "escalated",
  "reason": "block_escalation",
  "urgency": "standard",
  "escalation_path_key": "oncall",
  "escalation_path_name": "On-call engineers",
  "escalation_path_revision_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "pipeline_revision_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "block_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "targets": [
    {
      "type": "user",
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "name": "string"
    }
  ],
  "added_reviewers": [
    {
      "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "display_name": "string",
      "added_by_membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "added_by_display_name": "string",
      "created_at": "2026-09-08T12:02:11Z"
    }
  ],
  "team_policies": [
    {
      "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "team_name": "string",
      "policy_revision_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "revision": 1
    }
  ],
  "escalation": {
    "sequence": 1,
    "phase": "level",
    "urgency": "standard",
    "current_node_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "level_ordinal": 1,
    "level_count": 1,
    "repeat": 1,
    "next_escalation_at": "2026-09-08T12:02:11Z",
    "updated_at": "2026-09-08T12:02:11Z",
    "teams": [
      {
        "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "phase": "level",
        "current_node_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "level_ordinal": 1,
        "level_count": 1,
        "repeat": 1,
        "next_escalation_at": "2026-09-08T12:02:11Z"
      }
    ]
  },
  "created_at": "2026-09-08T12:00:00Z"
}

List who a request could be handed to

GET/api/v1/requests/{id}/reviewer-candidatesSession or API keyRequires request.decide

Active members who hold request.decide and are not yet reviewers of the request. Gated like deciding rather than by membership.read, so a targeted reviewer without the members page can still hand off.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

Response

Response codes

StatusBodyDescription
200object

Candidates sorted by name

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

candidatesarray<object>required

Example

GET /api/v1/requests/{id}/reviewer-candidates
curl -X GET "$WITHHUMAN_URL/api/v1/requests/{id}/reviewer-candidates" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "candidates": [
    {
      "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "display_name": "string",
      "email": "string"
    }
  ]
}

Add a reviewer to a pending request

POST/api/v1/requests/{id}/reviewersSession or API keyRequires request.decide

The handoff. Someone the request was routed to (or a holder of request.decide.unrouted) pulls one more active member who may decide into the request's routing. Widening never removes anyone and is audited as request.reviewer_added. Refused when the request is not pending or was never routed (409), when the actor is not targeted (403), or when the member is inactive or cannot decide (400).

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

Request body

membership_iduuidrequired

Response

Response codes

StatusBodyDescription
200ApprovalReview

The request's review after the widening

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

Who was asked to review a request when it entered human review. escalated pins an escalation path revision and the people it reaches for this request; default_queue means any authorized reviewer.

People added to the request's routing after it was pinned, oldest first. The same list the routing carries.

The reading person's own standing on the request. targeted says whether the pinned path reaches them for this request (directly, through a team, or by a later widening). decidable says whether a decision from them would pass the routing rule outright (yes), only with the outside_routing acknowledgement and request.decide.unrouted (break_glass), or not at all (no). reason names the rule in the way; it is absent when decidable is yes or the request is no longer pending. The decision itself still checks membership status, self-approval, and authentication freshness.

Example

POST /api/v1/requests/{id}/reviewers
curl -X POST "$WITHHUMAN_URL/api/v1/requests/{id}/reviewers" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
}'
200 response
{
  "routing": {
    "outcome": "escalated",
    "reason": "block_escalation",
    "urgency": "standard",
    "escalation_path_key": "oncall",
    "escalation_path_name": "On-call engineers",
    "escalation_path_revision_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "pipeline_revision_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "block_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "targets": [
      {
        "type": "user",
        "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "name": "string"
      }
    ],
    "added_reviewers": [
      {
        "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "display_name": "string",
        "added_by_membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "added_by_display_name": "string",
        "created_at": "2026-09-08T12:02:11Z"
      }
    ],
    "team_policies": [
      {
        "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "team_name": "string",
        "policy_revision_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
        "revision": 1
      }
    ],
    "escalation": {
      "sequence": 1,
      "phase": "level",
      "urgency": "standard",
      "current_node_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "level_ordinal": 1,
      "level_count": 1,
      "repeat": 1,
      "next_escalation_at": "2026-09-08T12:02:11Z",
      "updated_at": "2026-09-08T12:02:11Z",
      "teams": [
        {
          "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
          "phase": "level",
          "current_node_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
          "level_ordinal": 1,
          "level_count": 1,
          "repeat": 1,
          "next_escalation_at": "2026-09-08T12:02:11Z"
        }
      ]
    },
    "created_at": "2026-09-08T12:00:00Z"
  },
  "added_reviewers": [
    {
      "membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "display_name": "string",
      "added_by_membership_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "added_by_display_name": "string",
      "created_at": "2026-09-08T12:02:11Z"
    }
  ],
  "viewer": {
    "targeted": true,
    "decidable": "yes",
    "reason": "not_targeted"
  }
}

Read why a request needs a human and what has happened to it sinceHosted edition

GET/api/v1/requests/{id}/timelineSession or API keyRequires request.read

Product read only, gated by request.read alone. The pipeline's conclusion and the block that asked for a human, every judge assessment, the escalation steps, and the claim history, told from the request's own audit events, so a reviewer does not need audit.read to understand why they are being asked. Raw evaluation traces stay in the audit log. Routing, added reviewers, and the reader's standing are the review (GET /api/v1/requests/{id}/review), which every edition serves.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The request's id.

Response

Response codes

StatusBodyDescription
200RequestTimeline

The request's timeline

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

The completed evaluation as a reviewer reads it. The terminal block is the one whose outcome ended the pipeline; its fields are absent when the pipeline fell through its end or never ran.

claimsarray<ClaimEvent>required

What the escalation executor did for the request, oldest first. Empty for a default queue request.

audit_event_countintegerrequired

How many audit events the request has in total, for the link into the audit log.

Example

GET /api/v1/requests/{id}/timeline
curl -X GET "$WITHHUMAN_URL/api/v1/requests/{id}/timeline" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "pipeline": {
    "outcome": "approve",
    "reason_code": "string",
    "blocks_evaluated": 1,
    "terminal_block_key": "string",
    "terminal_block_name": "string",
    "terminal_block_type": "always",
    "terminal_block_reason": "string",
    "endpoint_reason": "string",
    "terminal_block_error_code": "string",
    "terminal_pipeline": {
      "scope": "organization",
      "agent_slug": "string",
      "revision": 1
    },
    "completed_at": "2026-09-08T12:02:11Z"
  },
  "assessments": [
    {
      "block_key": "string",
      "block_name": "string",
      "verdict": "approve",
      "confidence": "low",
      "rationale": "string",
      "model_label": "string",
      "provider": "string",
      "model": "string",
      "downgraded_for_confidence": true,
      "evaluated_at": "2026-09-08T12:02:11Z"
    }
  ],
  "claims": [
    {
      "kind": "claimed",
      "actor_display_name": "string",
      "occurred_at": "2026-09-08T12:02:11Z"
    }
  ],
  "escalations": [
    {
      "kind": "level_entered",
      "team_id": "string",
      "node_id": "string",
      "level_ordinal": 1,
      "level_count": 1,
      "urgency": "standard",
      "until": "2026-09-08T12:02:11Z",
      "iteration": 1,
      "occurred_at": "2026-09-08T12:02:11Z"
    }
  ],
  "audit_event_count": 1
}