---
title: "Register an agent"
method: POST
path: "/api/me/agents"
tags: ["Member Agents"]
---

# Register an agent

`POST /api/me/agents`

Register an agent on the caller's organization member profile.

Idempotent on `url`: re-posting the same `url` updates the entry in place rather than creating a duplicate. New entries return `201`; updates return `200`.

**True one-call storefront experience.** A third-party app holding only a user's OAuth token can `POST /api/me/agents` once and have the entire bootstrap chain materialize:

- If the caller has zero org memberships, the server auto-creates an organization (corporate or personal workspace based on the user's email domain) and the response includes `org_auto_created: true`.

- If the caller's org has no member profile, the server auto-creates a private profile (display name = organization name, `is_public: false`) and the response includes `profile_auto_created: true`.

Both auto-bootstraps are best-effort fallbacks. To customize org name / company_type / revenue_tier, or to control profile slug / brand identity / tagline, call `POST /api/organizations` and `POST /api/me/member-profile` explicitly before registering the agent. Tier transitions never happen via this path — go through the billing flow.

`type` is required and declared by the caller — the server does not infer it. Server-side smuggle protection still cross-checks the declared type against the agent's capability snapshot when one exists; if the snapshot contradicts the declaration without classifying it, the stored value is `unknown` and the dashboard surfaces the conflict for the owner to resolve.

`visibility: "public"` requires a paid AAO tier (Professional, Builder, Member, or Leader) and a verified primary domain on the organization (set via the Linked Domains UI). Non-API-tier callers (Explorer or no tier) who request `public` will have the entry stored as `members_only` instead, and the response will include a `visibility_downgraded` warning describing the coercion.

## Query parameters

- `org` string — WorkOS organization id to act on. Defaults to the caller's primary organization. Use this from a multi-org session (or when shelling with a user JWT) to target a non-primary org. Verification goes through WorkOS membership lookup; non-members get `403`.

## Request body

- MemberAgentInput — Request body for `POST /api/me/agents`. `type` is required — the owner declares it; the server never infers.
  - `url` string, uri, required
  - `type` 'brand' | 'rights' | 'measurement' | 'governance' | 'creative' | 'sales' | 'buying' | 'signals', required — Agent type the caller declares. Required on register; smuggle-protection still cross-checks against the capability snapshot when one exists. The server never infers `type` — the owner declares what kind of agent this is.
  - `name` string
  - `visibility` 'private' | 'members_only' | 'public' — Visibility tier on the registry catalog. `private` = profile owner only; `members_only` = AAO API-tier members on operator lookup; `public` = listed in the public catalog and reflected in the org's `brand.json` (requires a paid AAO tier — Professional, Builder, Member, or Leader).
  - `health_check_url` string, uri

## Response `200`

Agent already registered at this `url`; entry updated in place.

- MemberAgentResponse
  - `agent` MemberAgent, required — Agent entry stored on a member profile. `type` is required on read because every write surface declares it and the operator endpoint always emits it; a stored value of `unknown` is the smuggle-protection outcome (snapshot contradicted the declaration without classifying it) and is the only path that surfaces an agent without a real type.
    - `url` string, uri, required
    - `visibility` 'private' | 'members_only' | 'public', required — Visibility tier on the registry catalog. `private` = profile owner only; `members_only` = AAO API-tier members on operator lookup; `public` = listed in the public catalog and reflected in the org's `brand.json` (requires a paid AAO tier — Professional, Builder, Member, or Leader).
    - `type` 'brand' | 'rights' | 'measurement' | 'governance' | 'creative' | 'sales' | 'buying' | 'signals' | 'unknown', required — Agent type as stored on the registry. Server-side smuggle protection compares the caller's declaration against the capability snapshot (when one exists) and may stamp `unknown` if the snapshot contradicts the declaration without classifying it. `unknown` is reserved for that server-side outcome; clients cannot submit it.
    - `name` string
    - `health_check_url` string, uri — Optional fallback liveness URL used by the health probe when the protocol handshake fails.
  - `warnings` MemberAgentVisibilityWarning[]
    - `code` 'visibility_downgraded', required
    - `agent_url` string, required
    - `requested` 'public', required
    - `applied` 'members_only', required
    - `reason` 'tier_required', required
    - `message` string, required
  - `org_auto_created` boolean — Set to `true` when this `POST` was the caller's first interaction with the registry and the server auto-created the organization (display name derived from the user's email domain for corporate emails, or `<First Last>'s Workspace` for free-email providers). Combined with `profile_auto_created`, this is the one-call storefront experience: a third-party app holding only an OAuth token gets the org, profile, and registered agent in a single request.
  - `profile_auto_created` boolean — Set to `true` when this `POST` was the first agent registration on the caller's organization and the server auto-created a private member profile (display name = organization name, `is_public: false`). Absent on subsequent calls and on update-in-place. Surfaced so storefront-style integrations can show a "we set up your profile" hint without needing to detect the prior 404 → bootstrap → retry shape.

## Other responses

- `201` — Agent registered. When this is the first agent on a freshly created organization, the response includes `profile_auto_created: true`.
- `400` — Missing or invalid `url`, missing/invalid `type`, or the caller has memberships in other orgs but no primary org set — pass `?org=<id>` to target one explicitly. (Fresh users with no memberships at all hit the org auto-bootstrap path and do not see this error.)
- `401` — Authentication required
- `403` — `?org=` was supplied but the caller is not a member of that organization.
- `404` — Auto-bootstrap could not run (e.g. the organization has no name yet). Call `POST /api/me/member-profile` to create a profile explicitly, then retry.
- `429` — Rate limit exceeded

---

[API](https://skmtc.net/adcontextprotocol/apis/agenticadvertising-org-registry-api.md) · [All operations](https://skmtc.net/adcontextprotocol/apis/agenticadvertising-org-registry-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/adcontextprotocol/agenticadvertising-org-registry-api/revisions/9ea7fedf54c0/schema)
