---
title: "Create the consenting user's first agent inline (consent page)"
method: POST
path: "/oauth/consent/agent"
tags: ["OAuth"]
---

# Create the consenting user's first agent inline (consent page)

`POST /oauth/consent/agent`

Create the consenting user's first agent from the zero-agents consent page (P4).

The form is rendered only when the consenting user owns zero agents in
any status (the G12(b) first-run dead-end). This submit verifies the signed
single-use ``agent-create`` blob (bound to the consent handle AND the
authenticated subject — no ambient credential is honored, so a cross-site
form cannot drive it: it would need both the unguessable handle and a
blob minted for that very handle), re-validates the handle and the D7
client gate, provisions the user row if deferred provisioning left none
(an affirmative user action, unlike rendering), re-checks the zero-agents
predicate (an agent appearing in between skips creation — idempotent),
creates the agent through the same ``AgentService.create`` path as the
SPA (owner = the consenting user, default agent scopes, same audit +
event), and 303-redirects back into ``GET /oauth/consent`` where the new
agent renders pre-selected.

Failure arms: expired/tampered/replayed blob and expired handle → the
consent flow's standard ``invalid_consent`` error redirect; a gated
client → ``access_denied``; an invalid agent name → the form re-rendered
with the error inline and a fresh blob.

Creation posture (security review — the hybrid): the arm is decided
server-side AFTER the subject is resolved/provisioned, against the same
effective-permission math as POST /agents' ``agents:write`` gate. A
permissioned user gets the original behaviour (ACTIVE + 303 re-entry); an
unpermissioned one gets a PENDING agent (the POST /register posture) and
the awaiting-approval page. A per-subject ``set_if_absent`` slot claim
makes N parallel submits (N distinct blobs from N renders) create exactly
one agent — losers re-enter consent, which renders the picker or the
awaiting page as appropriate.

## Response `200`

Successful Response

- unknown

## Other responses

- `400` — Bad Request
- `422` — Unprocessable Entity
- `500` — Internal Server Error
- `503` — Service Unavailable

## Changes

- **2026-09-10** `cfb8387e3e80` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/jentic/apis/jentic-control-plane-api/changes/oauth/consent/agent/post.md)

---

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