# POST /v1/projects/:projectId/leased-accounts/request (/docs/api/reference/leased-accounts/request-lease)



<Endpoint method="POST" path="/v1/projects/:projectId/leased-accounts/request" auth="Bearer" scope="leased:write" phase="1" />

Ask for warmed TikTok accounts in a niche. This endpoint writes to an ops queue — Layers operations picks up the request, allocates accounts from the warmed pool, and attaches them to your project.

<Callout type="info">
  Lease provisioning is handled by Layers — permanently. Requests are accepted via this API; accounts appear in [`GET /v1/leased-accounts`](/docs/api/reference/leased-accounts/list-leased-accounts) once Layers assigns them. We warm accounts in specific niches by hand so the pool stays healthy.
</Callout>

Leased accounts are billed at **$150/account/month**, charged to the partner wallet on assignment — not on request. If ops fulfills a request partially (say you asked for 5 and we could only assign 3), the status comes back as `partial` and you're only billed for the 3.

<Parameters
  title="Path"
  rows="[
  { name: 'projectId', type: 'string', required: true, description: 'Project that will own the assigned accounts.' },
]"
/>

<Parameters
  title="Headers"
  rows="[
  { name: 'Idempotency-Key', type: 'string (UUID)', description: 'Recommended. Same key + same body replays for 24 hours — prevents double-queueing the same request if your side retries.' },
]"
/>

<Parameters
  title="Body"
  rows="[
  { name: 'projectId', type: 'string', required: true, description: 'Must match the path :projectId. Included in the body so the server can reject mismatched retries.' },
  { name: 'count', type: 'integer', required: true, description: 'How many accounts to lease. 1–50 per request.' },
  { name: 'niche', type: 'Niche', required: true, description: 'What kind of account you want. See the Niche shape below.' },
  { name: 'target', type: 'string', description: 'Free-form description of what content will run on these accounts. Helps ops pick the right pool.' },
  { name: 'note', type: 'string', description: 'Any extra context for ops. 2000 chars max.' },
  { name: 'requestId', type: 'string', description: 'Partner-created request id. If omitted, server generates one.' },
]"
/>

<Parameters
  title="Niche"
  rows="[
  { name: 'vertical', type: 'string', required: true, description: 'Broad category — coffee, fitness, mobile games, etc. Ops matches against the pool\'s tag set.' },
  { name: 'audience', type: 'string', description: 'Target audience description.' },
  { name: 'language', type: 'string', description: 'BCP-47 language tag. Determines which language pools we search.' },
  { name: 'geo', type: 'string[]', description: 'ISO country codes. Ops prefers accounts with followers in these regions.' },
]"
/>

## Example request [#example-request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl https://api.layers.com/v1/projects/prj_01HX9Y7K8M2P4RSTUV56789AB/leased-accounts/request \
      -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..." \
      -H "Idempotency-Key: 9a2f1e44-6b3c-4d19-9e8a-f2d7c1b5e777" \
      -H "Content-Type: application/json" \
      -d '{
        "projectId": "prj_01HX9Y7K8M2P4RSTUV56789AB",
        "count": 5,
        "niche": {
          "vertical": "coffee",
          "audience": "home baristas 25–40",
          "language": "en",
          "geo": ["US", "CA", "GB"]
        },
        "target": "Short-form brew tutorials; paid UGC-style creative for ads."
      }'
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    const { requestId } = await layers.leasedAccounts.request(
      {
        projectId: "prj_01HX9Y7K8M2P4RSTUV56789AB",
        count: 5,
        niche: {
          vertical: "coffee",
          audience: "home baristas 25–40",
          language: "en",
          geo: ["US", "CA", "GB"],
        },
        target: "Short-form brew tutorials; paid UGC-style creative for ads.",
      },
      { idempotencyKey: crypto.randomUUID() },
    );

    // poll requestId via getLeaseRequest
    ```
  </Tab>

  <Tab value="Python">
    ```python
    result = layers.leased_accounts.request(
        project_id="prj_01HX9Y7K8M2P4RSTUV56789AB",
        count=5,
        niche={
            "vertical": "coffee",
            "audience": "home baristas 25–40",
            "language": "en",
            "geo": ["US", "CA", "GB"],
        },
        target="Short-form brew tutorials; paid UGC-style creative for ads.",
        idempotency_key=str(uuid.uuid4()),
    )
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="202" description="Request accepted into the ops queue">
  ```json
  {
    "requestId": "lreq_01HXZR7K8M2P4RSTUV56789AB",
    "status": "requested",
    "submittedAt": "2026-04-18T19:24:11Z"
  }
  ```
</Response>

Poll [`GET /v1/leased-accounts/requests/:id`](/docs/api/reference/leased-accounts/get-lease-request) for progress. Typical turnaround is under 48 hours during business days in SF — longer for unusual niches. If something's holding up your request, ops will leave a note on the request row.

## Errors [#errors]

| Status | Code                | When                                                                           |
| ------ | ------------------- | ------------------------------------------------------------------------------ |
| 422    | `VALIDATION`        | `count` out of range, `niche.vertical` missing, `geo` contains a non-ISO code. |
| 401    | `UNAUTHENTICATED`   | Missing or invalid key.                                                        |
| 402    | `BILLING_EXHAUSTED` | Partner wallet wouldn't cover even one assignment. Request is not queued.      |
| 403    | `FORBIDDEN_SCOPE`   | Key lacks `leased:write`.                                                      |
| 404    | `NOT_FOUND`         | Project not in your organization.                                              |
| 409    | `CONFLICT`          | Same `Idempotency-Key` replayed with a different body.                         |
| 429    | `RATE_LIMITED`      | Write budget exhausted.                                                        |

## See also [#see-also]

* [`GET /v1/projects/:id/leased-accounts/requests/:requestId`](/docs/api/reference/leased-accounts/get-lease-request) — poll the request
* [`GET /v1/projects/:id/leased-accounts`](/docs/api/reference/leased-accounts/list-leased-accounts) — list assigned accounts once ops is done
* [Request leased accounts](/docs/api/guides/request-leased-accounts) — end-to-end walk-through
