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

# Create rubric

> Save a set of questions so they can be re-run by id

Save a rubric once and run it by `rubric_id` from then on.

Questions are validated with exactly the same rules as a live evaluation, so a rubric that saves is a rubric that runs. They are re-validated on every run too — a rubric is not trusted just because it was valid when stored.

## Request

### Headers

<ParamField header="Authorization" type="string" required>
  Bearer token — **your standard 60db API key** (`sk_…`), or a user JWT. There is no separate Judge credential.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  application/json
</ParamField>

### Body

<ParamField body="name" type="string" required>
  Unique per workspace, max 120 characters.
</ParamField>

<ParamField body="questions" type="object" required>
  Map of answer key → question, 1–32 entries. Same shape as [Evaluate](/api-reference/judge/evaluate).
</ParamField>

<ParamField body="description" type="string">
  What the rubric is for. Max 2,000 characters.
</ParamField>

<ParamField body="model" type="string" default="jev-latest">
  Default model for runs of this rubric. A request may still override it.
</ParamField>

<ParamField body="shared" type="boolean" default="false">
  Publish to the whole workspace. **Owner or admin only** — a member gets `403`.
</ParamField>

## Response

<ResponseField name="data" type="object">
  The saved rubric, including its new `id`. Returns **201**.
</ResponseField>

## Errors

| Status | Meaning                                                      |
| ------ | ------------------------------------------------------------ |
| `400`  | Missing name, or an invalid question — the message names it. |
| `403`  | `shared: true` requires owner or admin.                      |
| `409`  | A rubric with that name already exists in this workspace.    |

## Example

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.60db.ai/judge/rubrics \
    -H "Authorization: Bearer your-api-key" \
    -H "Content-Type: application/json" \
    -d '{
        "name": "Call QA",
        "description": "Tone, satisfaction and outcome on inbound calls",
        "questions": {
            "tone": {
                "type": "choice",
                "criteria": {
                    "professional": "Calm",
                    "dismissive": "Brushes off",
                    "unknown": "Unclear"
                }
            }
        },
        "shared": false
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.60db.ai/judge/rubrics', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer your-api-key',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      "name": "Call QA",
      "description": "Tone, satisfaction and outcome on inbound calls",
      "questions": {
        "tone": {
          "type": "choice",
          "criteria": {
            "professional": "Calm",
            "dismissive": "Brushes off",
            "unknown": "Unclear"
          }
        }
      },
      "shared": false
    }),
  });
  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.60db.ai/judge/rubrics",
      headers={
          "Authorization": "Bearer your-api-key",
          "Content-Type": "application/json",
      },
      json={
          "name": "Call QA",
          "description": "Tone, satisfaction and outcome on inbound calls",
          "questions": {
              "tone": {
                  "type": "choice",
                  "criteria": {
                      "professional": "Calm",
                      "dismissive": "Brushes off",
                      "unknown": "Unclear"
                  }
              }
          },
          "shared": false
      },
  )
  data = response.json()
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "success": true,
    "data": {
      "id": "a1b2c3d4-e5f6-4789-abcd-ef0123456789",
      "name": "Docs sample 22592",
      "description": "Used to capture a real response for the docs",
      "model": "jev-latest",
      "questions": {
        "tone": {
          "type": "choice",
          "criteria": {
            "unknown": "Unclear",
            "dismissive": "Brushes off",
            "professional": "Calm"
          }
        }
      },
      "question_count": 1,
      "shared": false,
      "is_mine": true,
      "created_at": "2026-09-28T13:19:50.210Z",
      "updated_at": null
    }
  }
  ```
</ResponseExample>
