Request leased TikTok accounts
Ask Layers for warmed-up accounts in a specific niche. Poll the request until they land. Release them when you're done.
What you'll build
A request-and-wait flow for leased TikTok accounts: submit a request for N accounts in a niche, poll until Layers assigns them, then list the assigned accounts against the customer's project. Later, release any the customer no longer needs.
This is not a self-serve provisioning flow — provisioning is manual at Layers, permanently by design.
How this works
Your request lands in an internal queue. An operator picks it up, allocates warmed accounts from the pool that match the niche, and binds them to the customer's project. The accounts then surface through the list endpoint as normal social accounts — they behave identically to OAuth-connected accounts once assigned.
Subscribe to the lease_request.assigned webhook to stop polling; it fires once the assignment is fulfilled. Finer-grained status transitions (in_review → provisioning → failed) are planned.
Billing kicks in at assignment, not at request — $150 per account per month, debited against your partner wallet.
The running example is Quinn's Coffee Co requesting 5 leased accounts in the specialty-coffee niche.
Submit the request
/v1/projects/:projectId/leased-accounts/request- Auth
- Bearer
- Scope
- leased:write
niche.vertical is the only required niche field, but the more you specify, the better the operator's match. target is a free-text note for the operator — audience geography, customer's growth goals, anything that helps them allocate.
curl -X POST "https://api.layers.com/v1/projects/$PROJECT_ID/leased-accounts/request" \
-H "Authorization: Bearer $LAYERS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"count": 5,
"niche": {
"vertical": "specialty-coffee",
"audience": "Urban coffee drinkers 24-40, iPhone-first",
"language": "en",
"geo": ["US-WA", "US-OR", "US-CA"]
},
"target": "Quinn is opening three new locations in Q3; accounts should skew PNW cafe culture.",
"note": "First lease for this customer"
}'import { randomUUID } from "node:crypto";
const res = await fetch(
`https://api.layers.com/v1/projects/${projectId}/leased-accounts/request`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LAYERS_API_KEY}`,
"Idempotency-Key": randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
count: 5,
niche: {
vertical: "specialty-coffee",
audience: "Urban coffee drinkers 24-40, iPhone-first",
language: "en",
geo: ["US-WA", "US-OR", "US-CA"],
},
target:
"Quinn is opening three new locations in Q3; accounts should skew PNW cafe culture.",
note: "First lease for this customer",
}),
},
);
const { requestId } = await res.json();import os
import uuid
import requests
res = requests.post(
f"https://api.layers.com/v1/projects/{project_id}/leased-accounts/request",
headers={
"Authorization": f"Bearer {os.environ['LAYERS_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"count": 5,
"niche": {
"vertical": "specialty-coffee",
"audience": "Urban coffee drinkers 24-40, iPhone-first",
"language": "en",
"geo": ["US-WA", "US-OR", "US-CA"],
},
"target": "Quinn is opening three new locations in Q3; accounts should skew PNW cafe culture.",
"note": "First lease for this customer",
},
)
request_id = res.json()["requestId"]{
"requestId": "lreq_01H9ZY3A2V...",
"status": "requested",
"submittedAt": "2026-04-18T17:45:02.312Z"
}Save the requestId. That's the handle your UI uses to show the customer what's pending.
Poll the request status
/v1/projects/:projectId/leased-accounts/requests/:requestId- Auth
- Bearer
- Scope
- leased:write
curl "https://api.layers.com/v1/projects/$PROJECT_ID/leased-accounts/requests/lreq_01H9ZY3A2V..." \
-H "Authorization: Bearer $LAYERS_API_KEY"Statuses: requested → assigned | partial | rejected.
requested— submitted, not yet fulfilled.assigned— allcountaccounts allocated.assignedSocialAccountIdscarries the bindings.partial— some of the accounts allocated; others couldn't be matched.notewill explain what the operator couldn't find.rejected— operator couldn't fulfill the request at all.noteexplains why — usually a niche with no current pool, or a conflicting geo constraint.
A fulfilled request:
{
"requestId": "lreq_01H9ZY3A2V...",
"status": "assigned",
"submittedAt": "2026-04-18T17:45:02.312Z",
"assignedAt": "2026-04-19T14:02:11.920Z",
"assignedSocialAccountIds": [
"sa_01H9ZY4A...", "sa_01H9ZY4B...", "sa_01H9ZY4C...", "sa_01H9ZY4D...", "sa_01H9ZY4E..."
],
"note": "All 5 accounts warmed PNW cafe content for 3+ weeks prior to assignment."
}Fulfillment lead time is typically 1–5 business days depending on how specific your niche is. A common vertical like fitness or productivity-apps clears in a day. An unusual combination like regional cuisine + specific-city can take the full week.
Poll at a slow cadence — checking once an hour is plenty. The request doesn't change state any faster than that.
List the assigned accounts
Once a request is assigned, the accounts show up in the list endpoint. They behave identically to OAuth-connected accounts — you schedule posts against their socialAccountId the same way.
/v1/projects/:projectId/leased-accounts- Auth
- Bearer
- Scope
- social:read
curl "https://api.layers.com/v1/projects/$PROJECT_ID/leased-accounts?status=active" \
-H "Authorization: Bearer $LAYERS_API_KEY"{
"items": [
{
"socialAccountId": "sa_01H9ZY4A...",
"projectId": "prj_01H9ZX5YV8...",
"handle": "@pnw.bean.hunt",
"followers": 8420,
"status": "active",
"assignedAt": "2026-04-19T14:02:11.920Z",
"nextRenewalAt": "2026-05-19T14:02:11.920Z",
"monthlyPriceCents": 15000
}
]
}From here the flow is identical to any other social account. Pin them as targets in POST /v1/content/:containerId/schedule and Layers publishes for you.
Release an account when the customer's done
/v1/leased-accounts/:id- Auth
- Bearer
- Scope
- leased:write
curl -X DELETE "https://api.layers.com/v1/leased-accounts/sa_01H9ZY4A..." \
-H "Authorization: Bearer $LAYERS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "reason": "Customer downgraded to 3 accounts" }'{
"socialAccountId": "sa_01H9ZY4A...",
"status": "released",
"releasedAt": "2026-05-02T11:10:41.023Z"
}Release cancels the monthly lease on the next billing boundary. Any posts already scheduled against the released account move to canceled status. Warn your customer before you release — they can't recover the handle afterwards; it returns to the warming pool.
Things worth knowing
- TikTok ToS. Leased and warmed accounts aren't explicitly sanctioned by TikTok's terms. If you productize this for your customers, they inherit exposure. Surface this in your onboarding flow.
- Moderation still applies. Leased accounts go through the same approval gate as any other social account on your project. Nothing ships unmoderated.
- Handles aren't portable. The customer doesn't own the handle. If they cancel, the account returns to the pool.