# Requests

Request approval for a tool call and retrieve its outcome.

## Create an approval request

`POST /v1/requests`

Submits one proposed tool call. The provider derives instance identity
from the credential. The response may already contain a terminal decision.

An idempotency key identifies one execution attempt. Repeating the same
input with the same key returns the existing request in its current state.
Reusing the key with different input returns an idempotency conflict.
Keys are scoped to the authenticated instance and operation.

The provider must retain the request and key whilst the request is pending
and for at least seven days (168 hours) after it becomes terminal, measured
from decision.decided_at. If the request is retained longer, its key must
be retained for the same period. For a request with a notification,
retain both until at least 24 hours after delivery is acknowledged or
retries end, if that is later. Submission retries do not extend retention.

Delivery is inherited from the instance and cannot be supplied on a
request. Recording a terminal outcome and its notification must be
durable together when delivery is configured, including immediate
decisions. Replaying creation does not create another notification.


Authentication: Instance Credential

- `Idempotency-Key` (required): An opaque key for safely retrying this operation. Generate it before the
first submission and reuse it only with the same input.

See [idempotency and retries](https://agentapprovalprotocol.io/specification/http#idempotency-and-retries)
and [retention periods](https://agentapprovalprotocol.io/specification/http#retention).


### Request: refund

```json
{
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m"
}
```

### Response 200

The request in its current state, including on an idempotent replay.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m",
  "status": "pending",
  "created_at": "2026-09-16T12:00:00Z",
  "deadline_at": "2026-09-16T12:30:00Z"
}
```

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m",
  "status": "approved",
  "created_at": "2026-09-16T12:00:00Z",
  "deadline_at": "2026-09-16T12:30:00Z",
  "decision": {
    "status": "approved",
    "note": "The duplicate charge has been confirmed.",
    "decided_at": "2026-09-16T12:02:00Z",
    "expires_at": "2026-09-16T12:07:00Z"
  }
}
```

### Response 201

The new request, pending or already terminal.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m",
  "status": "pending",
  "created_at": "2026-09-16T12:00:00Z",
  "deadline_at": "2026-09-16T12:30:00Z"
}
```

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m",
  "status": "approved",
  "created_at": "2026-09-16T12:00:00Z",
  "deadline_at": "2026-09-16T12:30:00Z",
  "decision": {
    "status": "approved",
    "note": "The duplicate charge has been confirmed.",
    "decided_at": "2026-09-16T12:02:00Z",
    "expires_at": "2026-09-16T12:07:00Z"
  }
}
```

### Response 400

The request is malformed or a field is invalid. Code invalid_webhook_url
identifies an unsafe or malformed receiver URL. Code
unsupported_delivery_type identifies an unsupported transport, including
webhook when the provider supports only synchronous mode.


- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 401

The credential is missing, expired, revoked or otherwise invalid.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 403

The credential does not permit the operation or access to this resource.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 409

The operation conflicts with existing state. Code idempotency_conflict
means the key was used with different input. Code already_terminal means
the request was approved, denied or expired before cancellation.
Code instance_deleted means a provisioning replay refers to a deleted instance.


- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

```json
{
  "error": {
    "type": "conflict",
    "code": "idempotency_conflict",
    "message": "The idempotency key was already used for a different request.",
    "request_id": "1184dfc5-0e86-4f88-9b68-882b1dc60467"
  }
}
```

### Response 429

The caller must reduce its request rate. Respect Retry-After when present.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

- `Retry-After`: The delay before retrying, in seconds or as an HTTP date.

### Response 500

The provider could not complete the operation. This does not permit tool execution.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 503

The provider is temporarily unable to serve the operation.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

- `Retry-After`: The delay before retrying, in seconds or as an HTTP date.

See [Schemas](/specification/reference/schemas) and [OpenAPI](/specification/reference/openapi) for all fields and constraints.

## Retrieve an approval request

`GET /v1/requests/{id}`

Returns the current request. With wait, holds the response until the
request becomes terminal or the wait ends. A completed wait can return
a pending request. Polling does not extend the approval deadline.


Authentication: Instance Credential

- `id` (required): The approval request's provider-assigned ID.

- `wait`: How long to wait for a terminal state. Capped at 30 seconds.
Omitting this parameter returns immediately.


### Response 200

The request in its current state, including on an idempotent replay.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m",
  "status": "pending",
  "created_at": "2026-09-16T12:00:00Z",
  "deadline_at": "2026-09-16T12:30:00Z"
}
```

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m",
  "status": "approved",
  "created_at": "2026-09-16T12:00:00Z",
  "deadline_at": "2026-09-16T12:30:00Z",
  "decision": {
    "status": "approved",
    "note": "The duplicate charge has been confirmed.",
    "decided_at": "2026-09-16T12:02:00Z",
    "expires_at": "2026-09-16T12:07:00Z"
  }
}
```

### Response 400

The request is malformed or a field is invalid. Code invalid_webhook_url
identifies an unsafe or malformed receiver URL. Code
unsupported_delivery_type identifies an unsupported transport, including
webhook when the provider supports only synchronous mode.


- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 401

The credential is missing, expired, revoked or otherwise invalid.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 403

The credential does not permit the operation or access to this resource.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 404

The resource is unavailable to the caller.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 429

The caller must reduce its request rate. Respect Retry-After when present.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

- `Retry-After`: The delay before retrying, in seconds or as an HTTP date.

### Response 500

The provider could not complete the operation. This does not permit tool execution.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 503

The provider is temporarily unable to serve the operation.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

- `Retry-After`: The delay before retrying, in seconds or as an HTTP date.

See [Schemas](/specification/reference/schemas) and [OpenAPI](/specification/reference/openapi) for all fields and constraints.

## Cancel an approval request

`DELETE /v1/requests/{id}`

Withdraws a pending request. Only its creating instance may call this
operation. Deleting the instance also cancels its pending requests.
Repeating cancellation returns the same cancelled request. No idempotency
key is needed. An approved, denied or expired request is unchanged and
returns 409 with code already_terminal. Cancellation ends active long polls.


Authentication: Instance Credential

- `id` (required): The approval request's provider-assigned ID.

### Response 200

The cancelled request, including on repeated cancellation.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "tool": "issue_refund",
  "arguments": {
    "payment_id": "payment_123",
    "amount": 4900,
    "currency": "GBP"
  },
  "timeout": "30m",
  "status": "cancelled",
  "created_at": "2026-09-16T12:00:00Z",
  "deadline_at": "2026-09-16T12:30:00Z",
  "decision": {
    "status": "cancelled",
    "decided_at": "2026-09-16T12:02:00Z"
  }
}
```

### Response 401

The credential is missing, expired, revoked or otherwise invalid.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 403

The credential does not permit the operation or access to this resource.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 404

The resource is unavailable to the caller.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 409

The operation conflicts with existing state. Code idempotency_conflict
means the key was used with different input. Code already_terminal means
the request was approved, denied or expired before cancellation.
Code instance_deleted means a provisioning replay refers to a deleted instance.


- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

```json
{
  "error": {
    "type": "conflict",
    "code": "idempotency_conflict",
    "message": "The idempotency key was already used for a different request.",
    "request_id": "1184dfc5-0e86-4f88-9b68-882b1dc60467"
  }
}
```

### Response 429

The caller must reduce its request rate. Respect Retry-After when present.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

- `Retry-After`: The delay before retrying, in seconds or as an HTTP date.

### Response 500

The provider could not complete the operation. This does not permit tool execution.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

### Response 503

The provider is temporarily unable to serve the operation.

- `X-Request-ID` (required): Identifies this HTTP exchange. Matches error.request_id on errors.

- `Retry-After`: The delay before retrying, in seconds or as an HTTP date.

See [Schemas](/specification/reference/schemas) and [OpenAPI](/specification/reference/openapi) for all fields and constraints.