curl --request POST \
--url https://api.onlyx.ai/v1/conversations/{conversationId}/handoff/resolve \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"note": "Re-sent the video as a free message; fan confirmed it plays."
}
'import requests
url = "https://api.onlyx.ai/v1/conversations/{conversationId}/handoff/resolve"
payload = { "note": "Re-sent the video as a free message; fan confirmed it plays." }
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({note: 'Re-sent the video as a free message; fan confirmed it plays.'})
};
fetch('https://api.onlyx.ai/v1/conversations/{conversationId}/handoff/resolve', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));Resolve a hand-off
Closes the open hand-off on this conversation, with an optional note saying what your team did. This can reach the fan: if the chat is still in handoff (nobody replied or took it over), it returns to the AI at once and the AI may answer the fan’s waiting message within seconds. If your team already replied or took the chat over, it stays with your team and resolving only closes the record. Returns 404 NOT_FOUND when the conversation has no open hand-off (so resolving twice is harmless), and 503 SENDING_DISABLED while sending through the API is switched off.
Scope: requires inbox:write.
Rate limit: 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.
Reaches fans: this operation can reach a real fan or change the live OnlyFans account. Confirm it with a person before calling it on their behalf.
curl --request POST \
--url https://api.onlyx.ai/v1/conversations/{conversationId}/handoff/resolve \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"note": "Re-sent the video as a free message; fan confirmed it plays."
}
'import requests
url = "https://api.onlyx.ai/v1/conversations/{conversationId}/handoff/resolve"
payload = { "note": "Re-sent the video as a free message; fan confirmed it plays." }
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({note: 'Re-sent the video as a free message; fan confirmed it plays.'})
};
fetch('https://api.onlyx.ai/v1/conversations/{conversationId}/handoff/resolve', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));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 conversation id (cnv_…).
40Body
Optional: what your team did, up to 300 characters.
300Response
The resolved hand-off.
The conversation that was handed off.
When the conversation was handed off.
The creator of that conversation.
The fan's name, for display.
The hand-off id (esc_…).
The specific situation, for people (for example "Asks for a refund").
A short summary of the situation when it was raised, or your team's note once resolved with one. null when there is none.
Why the AI handed off, as a stable code: welfare, prohibited_request, real_world, payment_dispute, custom_request, whale_risk, confusion or failed_delivery. More values may be added.
open until your team resolves it.
open, resolved