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

# Create Line Request

> Create a new phone or email line request for the authenticated workspace. REST endpoint in the Tuco AI iMessage API — bearer-token auth, JSON request/response.

<Note>
  Use this endpoint after the workspace already has an active Tuco subscription. If the request is included in the current plan, Tuco starts provisioning immediately. If the request requires an add-on, Tuco returns a hosted invoice link.
</Note>

## What This Endpoint Decides

You send the line details once, and Tuco decides what should happen next.

The response will always fall into one of these buckets:

* `provisioning`
  Tuco accepted the request immediately and has started setting up the line.
* `awaiting_payment`
  Tuco saved the request, but it needs payment before provisioning can begin.
* `subscription_required`
  The workspace needs an active base plan before it can request lines.
* `forbidden_line_type`
  The current plan does not allow that request, or the plan reached a hard cap with no paid expansion path.

## Authentication

Pass your workspace API key as a Bearer token, or use a Clerk session token.

```bash theme={null}
Authorization: Bearer tuco_xxxxxxxxxxxxx
```

***

## Request body

<ParamField body="firstName" type="string">
  Required. Display first name for the line.
</ParamField>

<ParamField body="lastName" type="string">
  Required. Display last name for the line.
</ParamField>

<ParamField body="channelType" type="string">
  Required line channel. Supported values: `"phone"` or `"email"`.
</ParamField>

<ParamField body="lineType" type="string">
  Optional for phone lines. Supported values: `"purchased"` or `"byon"`. Defaults to `"purchased"` when omitted.
</ParamField>

<ParamField body="email" type="string">
  Required for email lines. Also required for BYON phone lines.
</ParamField>

<ParamField body="phone" type="string">
  Required for BYON phone lines.
</ParamField>

<ParamField body="zipcode" type="string">
  Optional. Used for purchased phone provisioning when relevant.
</ParamField>

<ParamField body="state" type="string">
  Optional. Used for purchased phone provisioning when relevant.
</ParamField>

<ParamField body="forwardCallsTo" type="string">
  Optional. Forwarding destination for phone lines.
</ParamField>

<ParamField body="profileImageUrl" type="string">
  Optional. Avatar shown in Tuco.
</ParamField>

<ParamField body="idempotencyKey" type="string">
  Optional. You can also send this as the `Idempotency-Key` header. Reusing the same key returns the original response instead of creating a duplicate request.
</ParamField>

***

## Required field rules

| Request type         | Required fields                                                                 |
| -------------------- | ------------------------------------------------------------------------------- |
| Email line           | `firstName`, `lastName`, `channelType=email`, `email`                           |
| Purchased phone line | `firstName`, `lastName`, `channelType=phone`                                    |
| BYON phone line      | `firstName`, `lastName`, `channelType=phone`, `lineType=byon`, `email`, `phone` |

Extra fields are tolerated. Tuco validates the fields required for the declared request type.

### Default behavior for phone lines

If `channelType` is `phone` and `lineType` is omitted, Tuco treats the request as:

```json theme={null}
{ "lineType": "purchased" }
```

That means BYON validation only applies when you explicitly send `lineType: "byon"`.

***

## Example: included line

```bash theme={null}
curl -X POST "https://app.tuco.ai/api/line-requests" \
  -H "Authorization: Bearer tuco_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: line-req-001" \
  -d '{
    "firstName": "Sales",
    "lastName": "Line 1",
    "channelType": "phone",
    "lineType": "purchased"
  }'
```

### Success: provisioning (`201 Created`)

```json theme={null}
{
  "success": true,
  "status": "provisioning",
  "paymentRequired": false,
  "line": {
    "_id": "6a091e74542d9e3d645925ae",
    "firstName": "Sales",
    "lastName": "Line 1",
    "channelType": "phone",
    "lineType": "purchased",
    "provisioningStatus": "provisioning",
    "paymentStatus": "not_required"
  }
}
```

***

## Example: paid add-on line

```bash theme={null}
curl -X POST "https://app.tuco.ai/api/line-requests" \
  -H "Authorization: Bearer tuco_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: line-req-002" \
  -d '{
    "firstName": "Support",
    "lastName": "Email 2",
    "channelType": "email",
    "email": "support2@example.com"
  }'
```

### Success: awaiting payment (`201 Created`)

```json theme={null}
{
  "success": true,
  "status": "awaiting_payment",
  "paymentRequired": true,
  "paymentReason": "over_plan_limit",
  "paymentUrl": "https://invoice.stripe.com/...",
  "expiresAt": null,
  "line": {
    "_id": "6a09279daa903300e2530b0f",
    "firstName": "Support",
    "lastName": "Email 2",
    "channelType": "email",
    "lineType": "purchased",
    "provisioningStatus": "awaiting_payment",
    "paymentStatus": "awaiting_payment",
    "stripeInvoiceId": "in_123",
    "paymentLinkUrl": "https://invoice.stripe.com/..."
  }
}
```

***

## What To Do After You Create A Request

If the response is `provisioning`:

* keep the returned `line._id`
* poll `GET /api/line-requests/:id` for status updates

If the response is `awaiting_payment`:

* keep the returned `line._id`
* show the `paymentUrl` to the user
* after payment, poll `GET /api/line-requests/:id` until it changes to `provisioning`

You should not submit the same line details again after payment. The original request is the one that continues.

***

## One Request At A Time

Tuco blocks a new request only when the workspace already has a line request in `awaiting_payment`.

This prevents:

* duplicate unpaid requests
* accidental double purchases
* race conditions from retries

Lines already in `provisioning` do not block the next request.

***

## Error responses

| Status | When                                                                             | Body                                                                                                |
| ------ | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `400`  | Missing required fields or invalid types                                         | `{ "error": "..." }`                                                                                |
| `401`  | Missing or invalid API key / session                                             | `{ "error": "Unauthorized" }`                                                                       |
| `403`  | Workspace has no active subscription                                             | `{ "success": false, "status": "subscription_required", "message": "...", "redirect": "/billing" }` |
| `403`  | Line type is not allowed on the plan, or hard cap reached with no paid expansion | `{ "success": false, "status": "forbidden_line_type", "message": "..." }`                           |
| `409`  | Another line request is already waiting for payment                              | `{ "success": false, "status": "request_in_progress", "message": "...", "existingLine": { ... } }`  |
| `429`  | Rate limit exceeded                                                              | `{ "error": "Rate limit exceeded", "retryAfterMs": 1234 }`                                          |

***

## Notes

* Payment is always attached to the exact saved line request. The caller does not need to resubmit the payload after paying.
* The API uses the authenticated workspace. You cannot request lines for an arbitrary workspace id in the body.
* Retry safety is built in through idempotency support and workspace-level request locking.
