# Instances

Provision, retrieve, update and delete instances.

## Provision an instance

`POST /v1/instances`

Creates an instance within the provisioner token's scope and returns
its identity and credential. An instance credential cannot call this
operation. Providers may also offer other credential issuance paths.

Retries with the same idempotency key and input return the original
instance and issued credential, without creating another instance or
renewing the credential. Keys are scoped to the provisioner and operation.
Reusing a key with different input returns an idempotency conflict.

Optional delivery configures a webhook for the instance. The provisioner
supplies a separate signing secret already installed on the receiver.
Verification must succeed before creation commits or a credential is
issued. Failure returns 422 with code webhook_verification_failed and
creates no instance. Unsafe or unsupported delivery configuration returns
400. The signing secret is never returned. Successful retries do not
repeat verification. Replaying creation after instance deletion returns
409 with code instance_deleted and must not recreate the instance.

The provider must retain the key and original result for at least seven
days (168 hours) after instance creation. Retries do not extend this period.
Failed verification can be attempted again with the same key and input.
Concurrent same-key attempts must be coalesced and must not commit twice.


Authentication: Provisioner Token

- `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: polling

```json
{
  "instance_name": "codex-chris-laptop"
}
```

### Request: webhook

```json
{
  "delivery": {
    "type": "webhook",
    "url": "https://harness.example.com/aap/events",
    "registration_id": "8246931c-4ce0-4c15-a94a-e9c078ad06e2",
    "signing_secret": "whsec_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
  }
}
```

### Response 200

The instance and credential from an earlier submission with the same key.

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

```json
{
  "instance": {
    "id": "b29a43a7-1949-4b9f-9d61-b7ae66f85d31",
    "name": "codex-chris-laptop"
  },
  "credential": {
    "token": "example-instance-credential",
    "expires_at": "2026-09-17T12:00:00Z"
  }
}
```

### Response 201

The newly created instance and its issued credential.

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

```json
{
  "instance": {
    "id": "b29a43a7-1949-4b9f-9d61-b7ae66f85d31",
    "name": "codex-chris-laptop"
  },
  "credential": {
    "token": "example-instance-credential",
    "expires_at": "2026-09-17T12:00: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 422

The proposed receiver failed verification. No instance or configuration change is committed.

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

```json
{
  "error": {
    "type": "invalid_request",
    "code": "webhook_verification_failed",
    "message": "The webhook receiver could not be verified.",
    "param": "delivery",
    "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 instance

`GET /v1/instances/{id}`

Returns the current instance within the provisioner token's scope.
Credentials and webhook signing secrets are never included.
Deleted instances return 404.


Authentication: Provisioner Token

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

### Response 200

The instance configuration, or the original result on an update replay. Secrets are excluded.

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

```json
{
  "id": "b29a43a7-1949-4b9f-9d61-b7ae66f85d31",
  "name": "codex-chris-laptop",
  "delivery": {
    "type": "webhook",
    "url": "https://harness.example.com/aap/events",
    "registration_id": "8246931c-4ce0-4c15-a94a-e9c078ad06e2"
  }
}
```

### 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.

## Update an instance

`PATCH /v1/instances/{id}`

Updates fields within the provisioner token's scope. Omitted fields are
unchanged. A supplied delivery object replaces the entire configuration,
including its secret, after verification. A failed verification returns
422 with code webhook_verification_failed and changes nothing, including
the name. Null delivery removes the receiver and ends outstanding delivery.

Once committed, future attempts for all queued notifications use the new
URL and secret, including those for older requests. Notification IDs,
bodies and retry deadlines do not change. An attempt already in flight
can still reach the old receiver. Replacing delivery does not replay
notifications whose delivery has already ended. Deletion must take
precedence over an update still being verified.

Idempotency keys are scoped to the provisioner, instance ID and operation.
Same-key, same-input retries return the original successful response
without repeating verification or reapplying the update. Changed input
returns 409. Retain the key and original result for at least seven days
after the update commits. Retrying does not renew that period.
A replay against a deleted instance returns 404 and cannot restore it.
Failed verification can be attempted again with the same key and input.
Concurrent same-key attempts must be coalesced and must not commit twice.


Authentication: Provisioner Token

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

- `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: replaceReceiver

```json
{
  "delivery": {
    "type": "webhook",
    "url": "https://harness.example.com/aap/events",
    "registration_id": "8246931c-4ce0-4c15-a94a-e9c078ad06e2",
    "signing_secret": "whsec_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8="
  }
}
```

### Request: rename

```json
{
  "instance_name": "codex-chris-desktop"
}
```

### Response 200

The instance configuration, or the original result on an update replay. Secrets are excluded.

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

```json
{
  "id": "b29a43a7-1949-4b9f-9d61-b7ae66f85d31",
  "name": "codex-chris-laptop",
  "delivery": {
    "type": "webhook",
    "url": "https://harness.example.com/aap/events",
    "registration_id": "8246931c-4ce0-4c15-a94a-e9c078ad06e2"
  }
}
```

### 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 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 422

The proposed receiver failed verification. No instance or configuration change is committed.

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

```json
{
  "error": {
    "type": "invalid_request",
    "code": "webhook_verification_failed",
    "message": "The webhook receiver could not be verified.",
    "param": "delivery",
    "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.

## Delete an instance

`DELETE /v1/instances/{id}`

Retires an instance within the provisioner token's scope. Revokes all its
credentials, cancels its pending requests and ends all webhook delivery.
Existing terminal decisions stay unchanged. No cancellation notifications
are sent for this operation. Attempts already in flight may still arrive.
Deletion does not stop tool execution that has already begun.

The provider must serialize deletion with request creation, decisions and
configuration updates so no pending work or active credential is left
behind. Request and idempotency retention still apply. The provider keeps
a deletion record for at least seven days; repeated deletion returns 204
whilst that record is retained. Unknown IDs return 404. No idempotency key
is required. This operation never recreates an instance.


Authentication: Provisioner Token

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

### Response 204

The instance has been deleted, including on repeated deletion.

- `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.