curl --request POST \
--url https://api.onlyx.ai/v1/creators/{creatorId}/ai-content/levels/{levelId}/media \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"mediaIds": [
"4498297884",
"4498297885"
],
"role": "paid"
}
'import requests
url = "https://api.onlyx.ai/v1/creators/{creatorId}/ai-content/levels/{levelId}/media"
payload = {
"mediaIds": ["4498297884", "4498297885"],
"role": "paid"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({mediaIds: ['4498297884', '4498297885'], role: 'paid'})
};
fetch('https://api.onlyx.ai/v1/creators/{creatorId}/ai-content/levels/{levelId}/media', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"collections": [
{
"active": true,
"description": "A slow tease that ends in the shower.",
"folderId": "fld_1a2b3c4d5e6f7a8b9c0d",
"id": "col_2b3c4d5e6f7a8b9c0d1e",
"levelCount": 2,
"mode": "sequential",
"name": "Shower set",
"position": 1
}
],
"creatorId": "cre_8f2c1a9b0d7e4c3f2a1b",
"folders": [
{
"collectionCount": 1,
"id": "fld_1a2b3c4d5e6f7a8b9c0d",
"name": "Sexting",
"position": 1
}
],
"levels": [
{
"active": true,
"availableInPaidMessages": true,
"collectionId": "col_2b3c4d5e6f7a8b9c0d1e",
"description": "Two selfies in a towel.",
"free": true,
"highlight": "the one where I get ready",
"id": "set_3c4d5e6f7a8b9c0d1e2f",
"name": "Opener",
"paid": [],
"position": 1,
"preview": [
{
"durationSeconds": null,
"id": "4498297883",
"thumbnailUrl": "https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297883/thumbnail",
"type": "photo"
}
],
"priceCents": 0,
"stats": {
"purchased": 0,
"revenueCents": 0,
"sent": 40
},
"tags": [
"Solo",
"Teasing"
]
},
{
"active": true,
"availableInPaidMessages": true,
"collectionId": "col_2b3c4d5e6f7a8b9c0d1e",
"description": "Four-minute shower video.",
"free": false,
"highlight": null,
"id": "set_4d5e6f7a8b9c0d1e2f3a",
"name": "Shower video",
"paid": [
{
"durationSeconds": 241,
"id": "4498297884",
"thumbnailUrl": "https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297884/thumbnail",
"type": "video"
}
],
"position": 2,
"preview": [],
"priceCents": 1500,
"stats": {
"purchased": 9,
"revenueCents": 13500,
"sent": 31
},
"tags": [
"Shower"
]
}
],
"vault": {
"assigned": 3,
"total": 512,
"unassigned": 509
}
}Add media to a level
Places vault media on a level as paid (locked behind the price) or preview (the free teaser that sells it). A media item can be on only one level, so adding it here moves it from any other level. On a free level everything is stored as preview. A priced level needs at least one paid item before the AI can sell it. Returns the whole updated content board. Nothing is sent to fans: the AI uses active ladders in its own conversations. AI content writes are limited to 60 a minute per credential.
Scope: requires ai:write.
Rate limits: 60 changes per 60 seconds per credential — on top of the general limit of 120 requests per 60 seconds per credential.
Idempotency: send an Idempotency-Key header to make retries safe: a replay within 24 hours returns the original response with Idempotent-Replayed: true.
curl --request POST \
--url https://api.onlyx.ai/v1/creators/{creatorId}/ai-content/levels/{levelId}/media \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"mediaIds": [
"4498297884",
"4498297885"
],
"role": "paid"
}
'import requests
url = "https://api.onlyx.ai/v1/creators/{creatorId}/ai-content/levels/{levelId}/media"
payload = {
"mediaIds": ["4498297884", "4498297885"],
"role": "paid"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({mediaIds: ['4498297884', '4498297885'], role: 'paid'})
};
fetch('https://api.onlyx.ai/v1/creators/{creatorId}/ai-content/levels/{levelId}/media', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"collections": [
{
"active": true,
"description": "A slow tease that ends in the shower.",
"folderId": "fld_1a2b3c4d5e6f7a8b9c0d",
"id": "col_2b3c4d5e6f7a8b9c0d1e",
"levelCount": 2,
"mode": "sequential",
"name": "Shower set",
"position": 1
}
],
"creatorId": "cre_8f2c1a9b0d7e4c3f2a1b",
"folders": [
{
"collectionCount": 1,
"id": "fld_1a2b3c4d5e6f7a8b9c0d",
"name": "Sexting",
"position": 1
}
],
"levels": [
{
"active": true,
"availableInPaidMessages": true,
"collectionId": "col_2b3c4d5e6f7a8b9c0d1e",
"description": "Two selfies in a towel.",
"free": true,
"highlight": "the one where I get ready",
"id": "set_3c4d5e6f7a8b9c0d1e2f",
"name": "Opener",
"paid": [],
"position": 1,
"preview": [
{
"durationSeconds": null,
"id": "4498297883",
"thumbnailUrl": "https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297883/thumbnail",
"type": "photo"
}
],
"priceCents": 0,
"stats": {
"purchased": 0,
"revenueCents": 0,
"sent": 40
},
"tags": [
"Solo",
"Teasing"
]
},
{
"active": true,
"availableInPaidMessages": true,
"collectionId": "col_2b3c4d5e6f7a8b9c0d1e",
"description": "Four-minute shower video.",
"free": false,
"highlight": null,
"id": "set_4d5e6f7a8b9c0d1e2f3a",
"name": "Shower video",
"paid": [
{
"durationSeconds": 241,
"id": "4498297884",
"thumbnailUrl": "https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297884/thumbnail",
"type": "video"
}
],
"position": 2,
"preview": [],
"priceCents": 1500,
"stats": {
"purchased": 9,
"revenueCents": 13500,
"sent": 31
},
"tags": [
"Shower"
]
}
],
"vault": {
"assigned": 3,
"total": 512,
"unassigned": 509
}
}Authorizations
An API key (onx_sk_…) created in OnlyX under Settings → API & MCP, or an OAuth access token (onx_at_…) issued to a connected app. Send it as Authorization: Bearer <credential>. API keys may also be sent as X-API-Key: <key>.
Headers
Optional. A unique value (8 to 64 letters, digits, - or _; a UUID is ideal) that makes a retry safe: the same key with the same request within 24 hours returns the stored response, with Idempotent-Replayed: true, instead of doing the work twice. The same key with a different request is 409 IDEMPOTENCY_KEY_REUSED; while the first request still runs it is 409 IDEMPOTENCY_IN_PROGRESS. A malformed key is 400 VALIDATION_ERROR.
8 - 64^[A-Za-z0-9_-]{8,64}$Path Parameters
The creator id (cre_…).
The level (set) id (set_…).
Body
1 to 200 vault media ids.
1 - 200 elementsAn OnlyFans vault media id (a string of digits), or ox:<id> for an item of an OnlyX library.
1 - 40paid: locked behind the price. preview: the free teaser. On a free level everything is stored as preview.
paid, preview Response
The whole content board after the change.
A creator's whole AI content setup. Every AI content write returns the updated board.
Ladders, by position.
Show child attributes
Show child attributes
The creator this board belongs to.
Folders, by position.
Show child attributes
Show child attributes
Every level of every ladder, by ladder and then by rung.
Show child attributes
Show child attributes
How much of the vault the ladders use.
Show child attributes
Show child attributes