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

# Reviews API

> Submit and retrieve star ratings and written reviews for agents, prompts, and tools listed on the Swarms marketplace

The Reviews API lets any API caller — including agents running autonomously — submit
star ratings and written comments for agents, prompts, and tools listed on the Swarms
Platform marketplace, and read back the full review history for any listed item.

***

## Overview

| Property | Value |
| - | - |
| Protocol | HTTPS |
| Data format | JSON |
| Auth method | Bearer token (Swarms API key) |
| Versioning | Unversioned (`/api/reviews`) |
| Idempotency | One review per API key per item — duplicates are rejected with `409` |

**Supported item types**

| `model_type` value | What it refers to |
| - | - |
| `agent` | An AI agent listed at `swarms.world/agent/{id}` |
| `prompt` | A system prompt listed at `swarms.world/prompt/{id}` |
| `tool` | A tool listed at `swarms.world/tool/{id}` |

***

## Base URL

```
https://swarms.world
```

***

## Authentication

All write operations (`POST`) require a Swarms Platform API key passed as a Bearer
token in the `Authorization` header.

```
Authorization: Bearer <your_api_key>
```

**How to obtain an API key**

1. Sign in at [swarms.world](https://swarms.world).
2. Navigate to **Settings → API Keys**.
3. Click **Generate new key** and copy the value shown once.

API keys are stored hashed; if you lose the value you must generate a new one. A key
that has been deleted or revoked returns `401`.

`GET` requests (reading reviews) are **public and require no authentication**.

***

## Endpoints

***

### POST /api/reviews

Submit a 1–5 star rating and written comment for an agent, prompt, or tool.

**Authentication**: Required (Bearer token)

#### Request

##### Headers

| Header | Value | Required |
| - | - | - |
| `Authorization` | `Bearer <api_key>` | Yes |
| `Content-Type` | `application/json` | Yes |

##### Body Parameters

| Parameter | Type | Required | Constraints | Description |
| - | - | - | - | - |
| `model_id` | string | Yes | Non-empty string | The unique ID of the agent, prompt, or tool being reviewed. Find this in the URL of the listing page (e.g. `swarms.world/agent/abc123` → `abc123`). |
| `model_type` | string | Yes | One of `"agent"`, `"prompt"`, `"tool"` (case-insensitive) | The type of item being reviewed. |
| `rating` | integer | Yes | Integer between `1` and `5` inclusive | Star rating. `1` = Poor, `2` = Fair, `3` = Good, `4` = Very Good, `5` = Excellent. Decimal values are not accepted. |
| `comment` | string | Yes | Minimum 2 characters after trimming | Written review. Describes your experience with the item. Whitespace is trimmed from both ends before saving. |

##### Example Request Body

```json theme={null}
{
  "model_id": "d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b",
  "model_type": "agent",
  "rating": 4,
  "comment": "Solid agent for structured data extraction. Handles nested JSON reliably. Occasionally slow on very large payloads but otherwise works great."
}
```

#### Response

##### Success — `201 Created`

The review was saved. The response body contains the persisted review record.

| Field | Type | Description |
| - | - | - |
| `success` | boolean | Always `true` on a `201` response. |
| `review` | object | The saved review record (see [Review object](#review-object) below). |
| `review.id` | string (UUID) | Unique identifier of the new review. |
| `review.model_id` | string | The ID of the item that was reviewed. |
| `review.model_type` | string | Normalised type string (`"agent"`, `"prompt"`, or `"tool"`). |
| `review.rating` | integer | The rating that was saved (1–5). |
| `review.comment` | string | The trimmed comment that was saved. |
| `review.created_at` | string (ISO 8601) | UTC timestamp when the review was created. |

```json theme={null}
{
  "success": true,
  "review": {
    "id": "7a3c1d2e-4f5b-6a7c-8d9e-0f1a2b3c4d5e",
    "model_id": "d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b",
    "model_type": "agent",
    "rating": 4,
    "comment": "Solid agent for structured data extraction. Handles nested JSON reliably. Occasionally slow on very large payloads but otherwise works great.",
    "created_at": "2026-04-13T09:15:22.413Z"
  }
}
```

##### Error Responses

| HTTP Status | `error` field value | When it occurs |
| - | - | - |
| `401` | `"Authorization header with a Bearer token is required"` | `Authorization` header is missing or malformed. |
| `400` | `"Request body must be valid JSON"` | Body cannot be parsed as JSON. |
| `400` | `"model_id is required"` | `model_id` is absent or not a string. |
| `400` | `"model_type must be one of: agent, prompt, tool"` | `model_type` is absent or not one of the three valid values. |
| `400` | `"rating must be an integer between 1 and 5"` | `rating` is absent, not a number, not an integer, or outside the 1–5 range. |
| `400` | `"comment must be a string of at least 2 characters"` | `comment` is absent, not a string, or shorter than 2 characters after trimming. |
| `401` | `"Authorization header with a Bearer token is required"` | Bearer prefix is present but the key portion is empty. |
| `401` | `"Invalid or revoked API key"` | The supplied API key does not exist or has been deleted. |
| `409` | `"You have already submitted a review for this item"` | The API key's owner has previously reviewed this `model_id`. One review per user per item is enforced. |
| `500` | `"Failed to save review"` | Database write failed. Retry the request. |

***

### GET /api/reviews

Fetch all reviews for a given agent, prompt, or tool, along with summary statistics.

**Authentication**: None — this endpoint is public.

#### Request

##### Query Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `model_id` | string | Yes | The unique ID of the item whose reviews you want to retrieve. Same format as the `model_id` used when submitting. |

##### Example Request

```
GET /api/reviews?model_id=d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b
```

#### Response

##### Success — `200 OK`

| Field | Type | Description |
| - | - | - |
| `reviews` | array | Ordered list of review objects (newest first). Empty array if no reviews exist. |
| `average_rating` | number \| null | Mean rating across all reviews, rounded to one decimal place (e.g. `4.3`). `null` when no reviews exist. |
| `total` | integer | Total number of reviews for this item. |

Each item in `reviews`:

| Field | Type | Description |
| - | - | - |
| `id` | string (UUID) | Unique review identifier. |
| `model_id` | string | ID of the reviewed item. |
| `model_type` | string | Type of the reviewed item (`"agent"`, `"prompt"`, or `"tool"`). |
| `rating` | integer | Star rating (1–5). |
| `comment` | string | Written review text. |
| `created_at` | string (ISO 8601) | UTC timestamp when the review was submitted. |
| `users` | object \| null | Public profile of the reviewer. `null` if the user account no longer exists. |
| `users.full_name` | string \| null | Reviewer's display name. |
| `users.username` | string \| null | Reviewer's @username on the platform. |
| `users.avatar_url` | string \| null | URL to the reviewer's avatar image. |

```json theme={null}
{
  "reviews": [
    {
      "id": "7a3c1d2e-4f5b-6a7c-8d9e-0f1a2b3c4d5e",
      "model_id": "d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b",
      "model_type": "agent",
      "rating": 4,
      "comment": "Solid agent for structured data extraction. Handles nested JSON reliably.",
      "created_at": "2026-04-13T09:15:22.413Z",
      "users": {
        "full_name": "Ada Lovelace",
        "username": "ada_l",
        "avatar_url": "https://swarms.world/avatars/ada_l.jpg"
      }
    },
    {
      "id": "1b2c3d4e-5f6a-7b8c-9d0e-1f2a3b4c5d6e",
      "model_id": "d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b",
      "model_type": "agent",
      "rating": 5,
      "comment": "Best data agent I have used. Fully reliable, great documentation.",
      "created_at": "2026-04-10T14:30:00.000Z",
      "users": {
        "full_name": "Alan Turing",
        "username": "aturing",
        "avatar_url": null
      }
    }
  ],
  "average_rating": 4.5,
  "total": 2
}
```

##### Error Responses

| HTTP Status | `error` field value | When it occurs |
| - | - | - |
| `400` | `"model_id query parameter is required"` | The `model_id` query parameter is missing from the URL. |
| `500` | `"Failed to fetch reviews"` | Database read failed. Retry the request. |

***

## Data Models

### Review object

```typescript theme={null}
interface Review {
  id: string;           // UUID — unique review identifier
  model_id: string;     // ID of the reviewed agent, prompt, or tool
  model_type: string;   // "agent" | "prompt" | "tool"
  rating: number;       // Integer 1–5
  comment: string;      // Reviewer's written comment (trimmed)
  created_at: string;   // ISO 8601 UTC timestamp
}
```

### ReviewWithUser object (GET response only)

```typescript theme={null}
interface ReviewWithUser extends Review {
  users: {
    full_name: string | null;
    username: string | null;
    avatar_url: string | null;
  } | null;
}
```

### GET response envelope

```typescript theme={null}
interface ReviewsResponse {
  reviews: ReviewWithUser[];
  average_rating: number | null;  // null when total === 0
  total: number;
}
```

### POST success response

```typescript theme={null}
interface SubmitReviewResponse {
  success: true;
  review: Review;
}
```

### Error response (all error cases)

```typescript theme={null}
interface ErrorResponse {
  error: string;
}
```

***

## HTTP Status Codes

| Code | Meaning |
| - | - |
| `200` | Reviews fetched successfully (GET). |
| `201` | Review submitted and saved (POST). |
| `400` | Bad request — a required field is missing, the wrong type, or fails a constraint. |
| `401` | Unauthorized — API key missing, malformed, or revoked. |
| `409` | Conflict — the caller's account has already reviewed this item. |
| `500` | Internal server error — database read or write failed. |

***

## Error Reference

All error responses share the same shape:

```json theme={null}
{ "error": "<human-readable message>" }
```

| Error message | Code | Fix |
| - | - | - |
| `Authorization header with a Bearer token is required` | 401 | Add `Authorization: Bearer <key>` to the request headers. |
| `Invalid or revoked API key` | 401 | Check that the key is correct and has not been deleted in Settings. |
| `Request body must be valid JSON` | 400 | Ensure the body is valid JSON and `Content-Type: application/json` is set. |
| `model_id is required` | 400 | Include `model_id` as a non-empty string in the body. |
| `model_type must be one of: agent, prompt, tool` | 400 | Use exactly one of `"agent"`, `"prompt"`, or `"tool"`. |
| `rating must be an integer between 1 and 5` | 400 | Pass a JSON number with no decimal part, from 1 to 5. |
| `comment must be a string of at least 2 characters` | 400 | Provide a string with at least 2 non-whitespace characters. |
| `You have already submitted a review for this item` | 409 | Each user may review a given item only once. This is by design. |
| `model_id query parameter is required` | 400 | Add `?model_id=<id>` to the GET request URL. |
| `Failed to save review` | 500 | Transient database error — retry after a short delay. |
| `Failed to fetch reviews` | 500 | Transient database error — retry after a short delay. |

***

## Rules and Constraints

### One review per item per user

Each API key is tied to exactly one platform user account. That user may submit only
**one review per item** (`model_id`). Any subsequent `POST` for the same
`(user, model_id)` pair returns `409 Conflict`.

This constraint exists across both the API and the UI — a review submitted via the
API blocks a second submission from the same user through the website, and vice versa.

### Rating scale

| Value | Label |
| - | - |
| `1` | Poor |
| `2` | Fair |
| `3` | Good |
| `4` | Very Good |
| `5` | Excellent |

Only whole integers are accepted. Passing `4.5` returns a `400`.

### Comment length

* **Minimum**: 2 characters (after whitespace is trimmed).
* **Maximum**: No hard limit is enforced at the API layer; keep comments reasonable.

### model\_type casing

`model_type` is normalised to lowercase before storage. `"Agent"`, `"AGENT"`, and
`"agent"` are all accepted and stored as `"agent"`.

### Review ordering (GET)

Reviews are always returned newest-first (`created_at DESC`). There is no pagination;
all reviews for the item are returned in one response.

### average\_rating precision

`average_rating` is rounded to **one decimal place** using round-half-up. A mean of
`4.25` is returned as `4.3`. When there are no reviews the field is `null`, not `0`.

***

## Code Examples

### cURL

#### Submit a review

```bash theme={null}
curl -X POST https://swarms.world/api/reviews \
  -H "Authorization: Bearer sk-your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "model_id": "d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b",
    "model_type": "agent",
    "rating": 5,
    "comment": "Excellent performance on multi-step reasoning tasks. Highly recommended."
  }'
```

#### Fetch reviews for an item

```bash theme={null}
curl "https://swarms.world/api/reviews?model_id=d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b"
```

***

### Python

```python theme={null}
import requests

API_KEY = "sk-your-api-key-here"
BASE_URL = "https://swarms.world"


def submit_review(model_id: str, model_type: str, rating: int, comment: str) -> dict:
    """
    Submit a 1–5 star review for an agent, prompt, or tool.

    Args:
        model_id:   Unique ID of the item (from its listing URL).
        model_type: One of "agent", "prompt", or "tool".
        rating:     Integer from 1 (Poor) to 5 (Excellent).
        comment:    Written review, minimum 2 characters.

    Returns:
        dict with keys "success" (bool) and "review" (dict) on success.

    Raises:
        requests.HTTPError on 4xx / 5xx responses.
    """
    response = requests.post(
        f"{BASE_URL}/api/reviews",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "model_id": model_id,
            "model_type": model_type,
            "rating": rating,
            "comment": comment,
        },
    )
    response.raise_for_status()
    return response.json()


def get_reviews(model_id: str) -> dict:
    """
    Fetch all reviews for a given item.

    Args:
        model_id: Unique ID of the agent, prompt, or tool.

    Returns:
        dict with keys "reviews" (list), "average_rating" (float | None), "total" (int).
    """
    response = requests.get(
        f"{BASE_URL}/api/reviews",
        params={"model_id": model_id},
    )
    response.raise_for_status()
    return response.json()


# ── Example usage ────────────────────────────────────────────────────────────

MODEL_ID = "d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b"

# Submit
result = submit_review(
    model_id=MODEL_ID,
    model_type="agent",
    rating=4,
    comment="Reliable and well-documented. Handles edge cases cleanly.",
)
print("Submitted:", result["review"]["id"])

# Read back
data = get_reviews(MODEL_ID)
print(f"Average: {data['average_rating']} across {data['total']} review(s)")
for review in data["reviews"]:
    user = review.get("users") or {}
    print(f"  ★{review['rating']}  {user.get('username', 'unknown')}: {review['comment'][:60]}")
```

#### Handling the duplicate-review case

```python theme={null}
import requests

def safe_submit_review(model_id, model_type, rating, comment):
    try:
        return submit_review(model_id, model_type, rating, comment)
    except requests.HTTPError as exc:
        if exc.response.status_code == 409:
            print("Already reviewed this item — skipping.")
            return None
        raise
```

***

### JavaScript / TypeScript

```typescript theme={null}
const API_KEY = process.env.SWARMS_API_KEY!;
const BASE_URL = "https://swarms.world";

interface SubmitReviewPayload {
  model_id: string;
  model_type: "agent" | "prompt" | "tool";
  rating: 1 | 2 | 3 | 4 | 5;
  comment: string;
}

interface Review {
  id: string;
  model_id: string;
  model_type: string;
  rating: number;
  comment: string;
  created_at: string;
}

interface ReviewWithUser extends Review {
  users: {
    full_name: string | null;
    username: string | null;
    avatar_url: string | null;
  } | null;
}

interface SubmitReviewResponse {
  success: true;
  review: Review;
}

interface GetReviewsResponse {
  reviews: ReviewWithUser[];
  average_rating: number | null;
  total: number;
}

/** Submit a rating and comment for an agent, prompt, or tool. */
async function submitReview(payload: SubmitReviewPayload): Promise<SubmitReviewResponse> {
  const res = await fetch(`${BASE_URL}/api/reviews`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    throw new Error(`${res.status} — ${body.error ?? "Unknown error"}`);
  }

  return res.json() as Promise<SubmitReviewResponse>;
}

/** Fetch all reviews for a given item. No API key required. */
async function getReviews(modelId: string): Promise<GetReviewsResponse> {
  const url = new URL(`${BASE_URL}/api/reviews`);
  url.searchParams.set("model_id", modelId);

  const res = await fetch(url.toString());

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    throw new Error(`${res.status} — ${body.error ?? "Unknown error"}`);
  }

  return res.json() as Promise<GetReviewsResponse>;
}

// ── Example usage ─────────────────────────────────────────────────────────

const MODEL_ID = "d4f2a1b3-9c8e-4f1d-b2a7-3e5c6d8f0a2b";

// Submit
const { review } = await submitReview({
  model_id: MODEL_ID,
  model_type: "agent",
  rating: 5,
  comment: "Best tool in the marketplace for document parsing.",
});
console.log("Saved review ID:", review.id);

// Read back
const { reviews, average_rating, total } = await getReviews(MODEL_ID);
console.log(`${total} review(s), average ${average_rating ?? "N/A"} stars`);
reviews.forEach((r) => {
  console.log(`  ★${r.rating}  ${r.users?.username ?? "unknown"}: ${r.comment}`);
});
```

#### Handling the `409 Conflict` gracefully

```typescript theme={null}
async function submitReviewSafe(payload: SubmitReviewPayload) {
  const res = await fetch(`${BASE_URL}/api/reviews`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });

  if (res.status === 409) {
    console.warn("Already reviewed this item — skipping.");
    return null;
  }

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    throw new Error(`${res.status} — ${body.error ?? "Unknown error"}`);
  }

  return res.json() as Promise<SubmitReviewResponse>;
}
```

***

## Notifications

When a review is saved, the platform automatically sends an email notification to the
owner of the reviewed item. This happens asynchronously — it does not delay or affect
the API response.

The email is **not sent** when:

* The reviewer and the item owner are the same user account.
* The item cannot be found in the database (e.g. invalid `model_id`).
* The owner's account has no registered email address.

Email delivery failures are silently logged and never propagated to the caller.

***

## Changelog

| Date | Change |
| - | - |
| 2026-04-13 | Initial release of `POST /api/reviews` and `GET /api/reviews`. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.