> ## Documentation Index
> Fetch the complete documentation index at: https://docs.praison.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Recipe Registry API

> HTTP API endpoints for recipe registry server

# Recipe Registry API

HTTP API endpoints for the recipe registry server started via `praisonai serve registry`.

## Base URL + Playground

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Start registry server
praisonai serve registry --port 7777
```

**Base URL:** `http://127.0.0.1:7777`

## Endpoints

### GET /healthz

Health check endpoint.

<ParamField query="none" type="none">
  No parameters required.
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl http://127.0.0.1:7777/healthz
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests

  response = requests.get("http://127.0.0.1:7777/healthz")
  health = response.json()
  print(f"Status: {health['status']}")
  print(f"Auth required: {health['auth_required']}")
  ```

  ```javascript JavaScript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  const response = await fetch("http://127.0.0.1:7777/healthz");
  const health = await response.json();
  console.log(`Status: ${health.status}`);
  ```
</CodeGroup>

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "status": "healthy",
  "auth_required": true,
  "read_only": false,
  "version": "1.0.0"
}
```

### GET /v1/recipes

List all recipes in the registry.

<ParamField query="tags" type="string">
  Filter by tags (comma-separated)
</ParamField>

<ParamField query="limit" type="integer">
  Maximum number of results (default: 50)
</ParamField>

<ParamField query="offset" type="integer">
  Offset for pagination (default: 0)
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl http://127.0.0.1:7777/v1/recipes
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests

  response = requests.get("http://127.0.0.1:7777/v1/recipes")
  data = response.json()
  for recipe in data["recipes"]:
      print(f"- {recipe['name']} v{recipe['version']}")
  ```

  ```javascript JavaScript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  const response = await fetch("http://127.0.0.1:7777/v1/recipes");
  const { recipes } = await response.json();
  recipes.forEach(r => console.log(`- ${r.name} v${r.version}`));
  ```
</CodeGroup>

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "recipes": [
    {
      "name": "my-agent",
      "version": "1.0.0",
      "description": "A helpful AI agent",
      "tags": ["agent", "assistant"]
    }
  ],
  "total": 1
}
```

### GET /v1/recipes/{name}

Get information about a specific recipe.

<ParamField path="name" type="string" required>
  Recipe name
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl http://127.0.0.1:7777/v1/recipes/my-agent
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests

  response = requests.get("http://127.0.0.1:7777/v1/recipes/my-agent")
  info = response.json()
  print(f"Latest: {info['latest']}")
  print(f"Versions: {list(info['versions'].keys())}")
  ```
</CodeGroup>

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "name": "my-agent",
  "latest": "1.0.0",
  "versions": {
    "1.0.0": {
      "checksum": "sha256:abc123...",
      "published_at": "2024-01-15T10:30:00Z"
    }
  }
}
```

### GET /v1/recipes/{name}/{version}

Get information about a specific version.

<ParamField path="name" type="string" required>
  Recipe name
</ParamField>

<ParamField path="version" type="string" required>
  Version string (e.g., "1.0.0")
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests

  response = requests.get("http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0")
  version_info = response.json()
  print(f"Checksum: {version_info['checksum']}")
  ```
</CodeGroup>

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "name": "my-agent",
  "version": "1.0.0",
  "checksum": "sha256:abc123...",
  "published_at": "2024-01-15T10:30:00Z",
  "manifest": {
    "description": "A helpful AI agent",
    "tags": ["agent", "assistant"],
    "author": "praison"
  }
}
```

### GET /v1/recipes/{name}/{version}/download

Download a recipe bundle.

<ParamField path="name" type="string" required>
  Recipe name
</ParamField>

<ParamField path="version" type="string" required>
  Version string
</ParamField>

<ParamField header="If-None-Match" type="string">
  ETag for conditional download
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl -o my-agent-1.0.0.praison \
    http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0/download
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests

  response = requests.get(
      "http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0/download"
  )
  with open("my-agent-1.0.0.praison", "wb") as f:
      f.write(response.content)
  ```
</CodeGroup>

**Response:** Binary `.praison` bundle file

**Headers:**

* `Content-Type: application/gzip`
* `ETag: "sha256:abc123..."`

### POST /v1/recipes/{name}/{version}

Publish a recipe bundle. **Requires authentication** if token is configured.

<ParamField path="name" type="string" required>
  Recipe name
</ParamField>

<ParamField path="version" type="string" required>
  Version string
</ParamField>

<ParamField header="Authorization" type="string">
  Bearer token for authentication
</ParamField>

<ParamField body="bundle" type="string" required>
  Base64-encoded .praison bundle
</ParamField>

<ParamField body="force" type="boolean">
  Overwrite existing version (default: false)
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  # Encode bundle as base64
  BUNDLE=$(base64 -i my-agent-1.0.0.praison)

  curl -X POST http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0 \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $PRAISONAI_REGISTRY_TOKEN" \
    -d "{\"bundle\": \"$BUNDLE\"}"
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests
  import base64
  import os

  # Read and encode bundle
  with open("my-agent-1.0.0.praison", "rb") as f:
      bundle_b64 = base64.b64encode(f.read()).decode()

  response = requests.post(
      "http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0",
      headers={
          "Authorization": f"Bearer {os.environ['PRAISONAI_REGISTRY_TOKEN']}"
      },
      json={"bundle": bundle_b64}
  )
  result = response.json()
  print(f"Published: {result['name']}@{result['version']}")
  ```
</CodeGroup>

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "ok": true,
  "name": "my-agent",
  "version": "1.0.0",
  "checksum": "sha256:abc123...",
  "published_at": "2024-01-15T10:30:00Z"
}
```

### DELETE /v1/recipes/{name}/{version}

Delete a recipe version. **Requires authentication** if token is configured.

<ParamField path="name" type="string" required>
  Recipe name
</ParamField>

<ParamField path="version" type="string" required>
  Version string
</ParamField>

<ParamField header="Authorization" type="string">
  Bearer token for authentication
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl -X DELETE http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0 \
    -H "Authorization: Bearer $PRAISONAI_REGISTRY_TOKEN"
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests
  import os

  response = requests.delete(
      "http://127.0.0.1:7777/v1/recipes/my-agent/1.0.0",
      headers={
          "Authorization": f"Bearer {os.environ['PRAISONAI_REGISTRY_TOKEN']}"
      }
  )
  print(f"Deleted: {response.status_code == 200}")
  ```
</CodeGroup>

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "ok": true,
  "message": "Deleted my-agent@1.0.0"
}
```

### GET /v1/search

Search recipes by query.

<ParamField query="q" type="string" required>
  Search query (matches name, description, tags)
</ParamField>

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl "http://127.0.0.1:7777/v1/search?q=agent"
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  import requests

  response = requests.get(
      "http://127.0.0.1:7777/v1/search",
      params={"q": "agent"}
  )
  results = response.json()
  for r in results:
      print(f"- {r['name']}: {r['description']}")
  ```

  ```javascript JavaScript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  const response = await fetch("http://127.0.0.1:7777/v1/search?q=agent");
  const results = await response.json();
  results.forEach(r => console.log(`- ${r.name}: ${r.description}`));
  ```
</CodeGroup>

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
[
  {
    "name": "my-agent",
    "version": "1.0.0",
    "description": "A helpful AI agent",
    "tags": ["agent", "assistant"]
  }
]
```

## Authentication

When the server is started with `--token`, write operations require authentication:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Start server with token
praisonai serve registry --token $PRAISONAI_REGISTRY_TOKEN
```

**Header format:**

```
Authorization: Bearer <token>
```

**Protected endpoints:**

* `POST /v1/recipes/{name}/{version}` - Publish
* `DELETE /v1/recipes/{name}/{version}` - Delete

**Unprotected endpoints:**

* `GET /healthz` - Health check
* `GET /v1/recipes` - List
* `GET /v1/recipes/{name}` - Info
* `GET /v1/recipes/{name}/{version}` - Version info
* `GET /v1/recipes/{name}/{version}/download` - Download
* `GET /v1/search` - Search

## Errors

| Status | Description                          |
| ------ | ------------------------------------ |
| 200    | Success                              |
| 201    | Created (publish)                    |
| 304    | Not Modified (ETag match)            |
| 400    | Invalid request                      |
| 401    | Unauthorized (missing/invalid token) |
| 404    | Recipe or version not found          |
| 409    | Conflict (version exists, use force) |
| 500    | Server error                         |

**Error Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "error": "Recipe not found: my-agent",
  "code": 404
}
```

## CLI Equivalent

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# List recipes
praisonai recipe list --registry http://localhost:7777

# Search recipes
praisonai recipe search agent --registry http://localhost:7777

# Publish recipe
praisonai recipe publish ./my-recipe \
  --registry http://localhost:7777 \
  --token $TOKEN

# Pull recipe
praisonai recipe pull my-agent \
  --registry http://localhost:7777 \
  -o ./recipes
```

## Related

* [Recipe Registry](/docs/features/recipe-registry) - Python API reference
* [Recipe Registry Server](/docs/deploy/recipe-registry-server) - Server deployment
* [Recipe CLI](/docs/cli/recipe-registry) - CLI commands
