# Quotas (https://terac.com/docs/developers/guides/quotas)

Steer participant distribution with per-answer and cross-question targets on screening answers.

Quotas let you control how many participants you recruit for specific screening answers. Without quotas, Terac fills participants on a first-come basis. With quotas, recruitment is steered so each target is honored.

Quotas are expressed through **`cross_quotas`** — one entry per **cell**. A cell targets a combination of one or more screening answers:

* **One condition** — a simple per-answer quota (e.g. "at least 30 senior engineers").
* **Two or more conditions** — an interlocked cross-tab, so the sample stays balanced on every dimension at once (e.g. "at least 4 who are in Brazil **and** at an agency").

Cells reference screening questions by their `key`, and cells that belong to the same cross-tab share a `dimension` token so they are summed and balanced together.

> Quotas require screening questions. The API returns a `BAD_REQUEST` error if you provide `cross_quotas` without screening questions.

## Fields [#fields]

| Field                             | Type    | Description                                                                                                                                 |
| --------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `label`                           | string  | Human label for the cell, e.g. `"Senior engineers"` or `"Brazil × Agency"` (1–200 characters).                                              |
| `conditions`                      | array   | One condition per dimension (1–26). One condition = a simple per-answer quota; two or more interlock a cross-tab across distinct questions. |
| `conditions[].screening_question` | string  | The `key` of a screening question — one dimension of the cell.                                                                              |
| `conditions[].answer`             | string  | An answer of that question, by its text. For a grid source use `"Row: Column"`.                                                             |
| `conditions[].operator`           | string  | `eq` (selected that answer, default) or `ne` (did not).                                                                                     |
| `join`                            | string  | How the conditions combine: `and` (default) or `or`.                                                                                        |
| `target`                          | integer | Participant count for this cell (positive).                                                                                                 |
| `quota_type`                      | string  | How the count is enforced: `minimum` (default), `maximum`, or `exact`.                                                                      |
| `dimension`                       | string  | Optional. Cells sharing a `dimension` are summed as one interlocked cross-tab. Use one token per cross-tab.                                 |

`quota_type` controls how each cell's `target` is enforced:

| `quota_type` | Meaning                                                                                                |
| ------------ | ------------------------------------------------------------------------------------------------------ |
| `minimum`    | At least this many. A floor — recruitment prioritizes the cell while it is short. This is the default. |
| `maximum`    | At most this many. A cap — applicants who match are screened out once the cell is full.                |
| `exact`      | Both a floor and a cap — recruit exactly this many.                                                    |

The sum of cell targets does not need to equal `num_participants`. Recruitment stops when **both** conditions are true: every `minimum`/`exact` cell is met, and `num_participants` is reached. `maximum` cells never extend recruitment; they only screen out once full.

## Simple quota (one condition) [#simple-quota-one-condition]

You want 60 participants, with a floor on senior reviewers and a cap on juniors — one cell per answer, each on the same question.

```json
{
  "num_participants": 60,
  "screening_questions": [
    {
      "key": "code_reviews",
      "text": "How many code reviews do you perform per week?",
      "pick": "one",
      "answers": [
        { "text": "5 or more", "qualify_logic": "must_one_of" },
        { "text": "2-4", "qualify_logic": "may" },
        { "text": "0-1", "qualify_logic": "reject" }
      ]
    }
  ],
  "cross_quotas": [
    {
      "label": "Senior reviewers",
      "conditions": [
        { "screening_question": "code_reviews", "answer": "5 or more" }
      ],
      "target": 30,
      "quota_type": "minimum"
    },
    {
      "label": "Occasional reviewers",
      "conditions": [{ "screening_question": "code_reviews", "answer": "2-4" }],
      "target": 20,
      "quota_type": "maximum"
    }
  ]
}
```

Recruitment continues until you have at least 30 who answered "5 or more" and 60 total, while never accepting more than 20 who answered "2-4".

## Cross-question quota (two or more conditions) [#cross-question-quota-two-or-more-conditions]

You want 40 participants, balanced across country **and** organization type. Each cell interlocks two questions; both cells share a `dimension` so they form one cross-tab.

```json
{
  "num_participants": 40,
  "screening_questions": [
    {
      "key": "country",
      "text": "Where are you based?",
      "pick": "one",
      "answers": [
        { "text": "Brazil", "qualify_logic": "may" },
        { "text": "Mexico", "qualify_logic": "may" }
      ]
    },
    {
      "key": "org_type",
      "text": "What kind of organization do you work for?",
      "pick": "one",
      "answers": [
        { "text": "Agency", "qualify_logic": "may" },
        { "text": "In-house", "qualify_logic": "may" }
      ]
    }
  ],
  "cross_quotas": [
    {
      "label": "Brazil × Agency",
      "dimension": "country_x_org",
      "conditions": [
        { "screening_question": "country", "answer": "Brazil" },
        { "screening_question": "org_type", "answer": "Agency" }
      ],
      "target": 4,
      "quota_type": "minimum"
    },
    {
      "label": "Brazil × In-house",
      "dimension": "country_x_org",
      "conditions": [
        { "screening_question": "country", "answer": "Brazil" },
        { "screening_question": "org_type", "answer": "In-house" }
      ],
      "target": 8,
      "quota_type": "minimum"
    }
  ]
}
```

Recruitment honors both cells independently: at least 4 participants who are in Brazil and at an agency, and at least 8 who are in Brazil and in-house.