# Submit a feasibility request (https://terac.com/docs/developers/reference/requestFeasibility)

`POST https://terac.com/api/external/v2/feasibility/requests`

Submit a feasibility request: can Terac source a panel for this task, and at what CPI (cost per participant).

This is an async request-reply. The response comes back immediately with status RECEIVED and no CPI
(costPerParticipant is null). Terac prices it out of band, either automatically within seconds or by
routing it to a person, so poll GET /feasibility/requests/{requestId} rather than assuming a turnaround.

Only what you send here is priced: taskDescription, panelDescription, and the count and timeline. The
filters, screening questions and tasks on the opportunity you build later are not part of the brief that
was priced, so a confirmed CPI applies to the scope described here and not to a materially different one.

Once RESPONDED, create the opportunity with POST /opportunities and pass feasibility_request_id to price
it from that confirmed CPI (Terac skips the autonomous estimate), then launch it. The request stays
RESPONDED until that study launches, and is closed as won at launch rather than at create.

## Authorization

Requires a Bearer token via the `Authorization` header.

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

## Request Body (required)

`Content-Type: application/json`

- `taskDescription` (string) **(required)**: What participants will do (interview, survey, usability test, ...) and for how long, up to 10,000 characters. Half of the brief that gets priced.
- `panelDescription` (string) **(required)**: Who the participants must be: role, seniority, industry, market, and anything that rules someone out, up to 10,000 characters. The other half of the priced brief.
- `submissionCount` (integer): How many completed participants you need, if known.
- `timelineHours` (integer): The turnaround you are asking Terac for, in hours.
- `payRateFrequency` (string): one of: `ONE_TIME`, `HOURLY`, `PER_TASK`: How the work is paid: ONE_TIME (per complete), HOURLY, or PER_TASK. Omit when the brief does not say; do not guess.
- `loiMinutes` (integer): Minutes one participant spends on the task. Not the turnaround.
- `requestorEmail` (string): Who Terac should contact about this request. Defaults to the email of the API key's owner.

## Responses

### 200: The new request, `RECEIVED` and not priced yet, with the dashboard page where its price will land.

- `id` (string) **(required)**
- `status` (string) **(required)**: one of: `RECEIVED`, `RESPONDED`, `WON`, `LOST`, `NOT_PURSUED`
- `source` (string) **(required)**
- `taskDescription` (string) **(required)**
- `panelDescription` (string) **(required)**
- `submissionCount` (integer, nullable) **(required)**
- `timelineHours` (integer, nullable) **(required)**
- `payRateFrequency` (string, nullable) **(required)**: one of: `ONE_TIME`, `HOURLY`, `PER_TASK`, `null`: What costPerParticipant is denominated in once priced: ONE_TIME (per complete), HOURLY, or PER_TASK. Null until the brief states it.
- `loiMinutes` (integer, nullable) **(required)**: Minutes one participant spends on the task. Distinct from timelineHours, which is Terac's turnaround.
- `costPerParticipant` (string, nullable) **(required)**
- `respondedAt` (string, nullable) **(required)**
- `createdAt` (string) **(required)**
- `dashboard_url` (string, nullable) **(required)**: The organization's feasibility requests and the incentives Terac quoted back. There is no page for a single request, so this list is the only feasibility link; give it after you request feasibility or when the customer asks where a quote went. Null if Terac cannot resolve the organization or project this link belongs to.
### 400: Invalid input data

- `message` (string) **(required)**: The error message
- `code` (string) **(required)**: The error code
- `issues` (array): An array of issues that were responsible for the error
  - `message` (string) **(required)**
### 401: The API key is missing, invalid, disabled, expired or revoked, its owner no longer exists, or it is not linked to an organization. The body is nested under `error`.

- `error` (object) **(required)**
  - `code` (string) **(required)**: one of: `UNAUTHORIZED`: The error code.
  - `message` (string) **(required)**: What went wrong.
### 403: Either the account that owns the API key is banned or deleted (from the key check, nested under `error`), or the key's owner lacks the organization permission this operation needs (from the operation, with `code` and `message` at the top level).

- One of: API key error (403)
  - `error` (object) **(required)**
    - `code` (string) **(required)**: one of: `FORBIDDEN`: The error code.
    - `message` (string) **(required)**: What went wrong.
- One of: Insufficient access error (403)
  - `message` (string) **(required)**: The error message
  - `code` (string) **(required)**: The error code
  - `issues` (array): An array of issues that were responsible for the error
    - `message` (string) **(required)**
### 429: The API key is rate limited. A key accepts 100 requests, then refuses every request until more than 60 seconds pass with no accepted request; refused requests do not extend the wait. Wait the number of seconds in `Retry-After`, then retry. The body is nested under `error`.

- `error` (object) **(required)**
  - `code` (string) **(required)**: one of: `RATE_LIMITED`: The error code.
  - `message` (string) **(required)**: What went wrong.
### 500: Internal server error

- `message` (string) **(required)**: The error message
- `code` (string) **(required)**: The error code
- `issues` (array): An array of issues that were responsible for the error
  - `message` (string) **(required)**