---
title: "Register From Manifest"
method: POST
path: "/api/v1/registry/register"
tags: ["registry"]
---

# Register From Manifest

`POST /api/v1/registry/register`

## Request

- Base URL: `https://api.badgeia.com`
- URL: `https://api.badgeia.com/api/v1/registry/register`
- Auth: none declared

Discover an agent manifest and register it in the platform.

Fetches the manifest, extracts metadata, and creates the agent record.
If an agent with the same name already exists, returns 409.

Requires authentication — the resulting agent is stamped with
`user_id = user.id` so ownership / private-agent gating works
consistently with directly-created agents.

## Request body

- ManifestDiscoverRequest: Request to discover an agent from a URL.
  - `url` string, required: Base URL of the agent (manifest fetched from {url}/.well-known/agent.json)

## Response `201`

Successful Response

- AgentRead
  - `name` string, required
  - `description` string, nullable
  - `endpoint` string, nullable
  - `id` string, uuid, required
  - `user_id` string, uuid, nullable
  - `ownership_scope` 'personal' | 'workspace' | 'system'
  - `team_id` string, uuid, nullable
  - `can_edit` boolean
  - `can_run_configured` boolean
  - `credential_reconnect_required` boolean
  - `architecture_staleness` object, nullable
  - `connection_retired` boolean
  - `has_endpoint` boolean
  - `workspace_role` 'owner' | 'admin' | 'member' | 'viewer', nullable
  - `has_otlp_ingest_token` boolean
  - `is_active` boolean, required
  - `is_public` boolean
  - `is_reference` boolean
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `connection_mode` 'http_endpoint' | 'daemon_pull' | 'openai_assistant' | 'customer_llm', nullable
  - `daemon_last_seen_at` string, date-time, nullable
  - `customer_llm_provider` 'gemini' | 'openai_compat', nullable
  - `customer_llm_key_last4` string, nullable
  - `manifest_url` string, nullable
  - `provider_name` string, nullable
  - `provider_url` string, nullable
  - `model_name` string, nullable
  - `model_provider` string, nullable
  - `architecture` string, nullable
  - `schema_version` string, nullable
  - `agent_version` string, nullable
  - `domains` string, nullable
  - `tags` string, nullable
  - `verified_at` string, date-time, nullable
  - `registry_status` string
  - `variant_of` string, uuid, nullable
  - `payload_schema` 'badge_native' | 'openai_chat' | 'anthropic_messages'
  - `created_by_user_id` string, uuid, nullable: UUID of the workspace member who registered this agent (null for transferred/legacy rows whose creator was never recorded, or whose creator account was deleted — the FK is ON DELETE SET NULL). Populated ONLY on GET /agents?team_id=... for a caller with workspace-analytics permission (Owner/Admin); null on every other path and for members and viewers. The raw id only — no name, no email.
  - `composite_score` number, nullable: Cross-task overall composite score, ALREADY on a 0-100 scale — never multiply or divide it (CLAUDE.md rule 2). Null when the agent has no cross-task Score row yet. Agent-level and NOT workspace-scoped: it is derived from every run the agent ever completed, including any from before a transfer, and is the same number a public agent shows on the Talent Pool. Populated ONLY on GET /agents?team_id=... for a caller with workspace-analytics permission; null on every other path.
  - `total_runs` integer, nullable: Count of COMPLETED runs this agent performed FOR THIS WORKSPACE. Runs from before a transfer are personal-scoped and are excluded, so a freshly transferred agent reports 0 here while its composite score still reflects them. 0 (not null) when there are none. Populated ONLY on GET /agents?team_id=... for a caller with workspace-analytics permission; null on every other path.
  - `last_run_at` string, date-time, nullable: When this agent last started a completed run FOR THIS WORKSPACE. Derived from the run START (SEC-RUNS-009), not its completion. Null when there are no completed workspace runs — pre-transfer personal runs never surface here. Populated ONLY on GET /agents?team_id=... for a caller with workspace-analytics permission; null on every other path.
  - `verified_state` 'verified' | 'simulated' | 'unverified', nullable: Execution provenance for this agent's signed WORKSPACE runs: 'verified' (has a signed real-execution workspace run), 'simulated' (signed workspace runs, all mock), or 'unverified' (no signed workspace run at all — the value, not null, when the field is populated). A pre-transfer personal run cannot light this, so it may read 'unverified' while the public board shows a ✓ for the same agent. Populated ONLY on GET /agents?team_id=... for a caller with workspace-analytics permission; null on every other path.
  - `has_openai_credentials` boolean, required
  - `has_customer_llm_key` boolean, required
  - `ml_bom` object, nullable, required
  - `provenance_public_key_set` boolean, required

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/badgeia/apis/badge.md) · [All operations](https://skmtc.dev/badgeia/apis/badge/llms.txt) · [OpenAPI document](https://skmtc.dev/badgeia/apis/badge/revisions/7e7f7fee8b77?raw)
