Turn any inbox you own — a helpdesk, a ticketing system, your own app’s chat — into a SlyOS channel. Send messages in; SlyOS writes the replies with the account’s own Brain: what the business has taught it, the voice it has learned, and the conversation so far. You send each reply through your own system.
Authentication
Every request sends Authorization: Bearer <key>. Keys starting sly_test_ are the sandbox: free, and they reach nobody. Keys starting sly_live_ are live. A sandbox key creates and lists sandbox channels; a live key, live ones — and neither can reach the other's messages, cards or replies: an id from the other environment is a 404. Sandbox drafts are free and limited to 50 in any 24 hours. Each operation names the scope its key must carry, and a key without it is refused 403 missing_scope. A missing, malformed or revoked key is refused 401 unauthorized, always with the same sentence.
What costs money
Only POST /v1/developer/drafts, only on a live key, and only when a reply is produced:
- From 2026-09-01: 10¢ per AI response (price version
2026-09-01)
Taking messages in, reading replies back, reporting deliveries, usage and wallet lookups are free. So is everything in the sandbox. A reply that is refused, fails, or is judged unnecessary is not charged.
Retrying safely
POST /v1/developer/messages: the same external_message_id on the same channel is stored once; the repeat answers 200 with duplicate: true.POST /v1/developer/drafts: generation_id is the idempotency key for the charge, and it is yours: unique within your account and the key’s environment. Derive it from the message_id SlyOS returned — <message_id>:reply-1 — so it is unique and the same on a retry. Repeating a generation_id that already has a reply gets that reply back with 200 and replayed: true, charged nothing (billed_cents: 0; on a live key, already_charged: true). While the first request is still being drafted, the repeat answers 409 generation_in_progress with Retry-After: retry with the same id. The same id sent for a different conversation is refused 409 generation_id_conflict, never answered with the first conversation’s reply.POST /v1/developer/deliveries: send your own external_message_id, and a repeated report is one message.
Teach SlyOS your business
A reply is only as good as what SlyOS knows about the business it speaks for. Before the first one, hand it the material your answers must agree with — every reply is then given your rules and the passages nearest the message, and written in the voice SlyOS has learned for the account:
- Links and whole sites.
POST /v1/developer/knowledge/sources with {"url": "…"} reads one page — your pricing, your policies, a regulation your answers must respect. Add "crawl": true to read the whole site. - Files. The same call as
multipart/form-data, with the file in a file field: PDF, Word, plain text, Markdown or CSV. It is read to the end. - Rules.
"rules": true (a rules=true form field, for a file) marks a source replies must follow rather than draw on: terms, a returns policy, a regulation. Every reply carries the rules whole while they fit in one reply; past that, each reply gets the rules nearest its message, and the source says rules_fit: false. - Who you are.
PUT /v1/developer/knowledge/profile says what the business is and how it wants to sound.
Sources are read in the background: status goes queued, processing, then ready — or failed, with status_reason saying why. A web page is read without running its scripts, so a page that builds its content with JavaScript (prices drawn from a script, a template filled in after it loads) can be missing what a visitor sees: the source is then ready with a warning naming those pages in incomplete_pages — add that text as a file, or as a single link to a page that shows it. Adding and changing them needs a live key carrying brain:write — sandbox and live replies share them, so a sandbox key may only read them; listing them, brain:read. GET /v1/developer/knowledge/sources/{sourceId}/passages shows exactly what was read. Replies use what you add, the conversation they answer and that customer’s earlier ones — never another customer’s, and never a sandbox conversation in a live reply. They also use everything SlyOS knows about the account owner: facts from their own conversations and the ones they told it, their past replies on their other channels, their documents, calendar and saved details, and their About you. The owner can turn that off on the Developer screen (use_personal_context); a key cannot change it. Off, a reply still uses the owner’s name, rules and writing style. Sources added with a key belong to its project unless the request sends "scope": "account". When sources disagree. Each reply is given the passages nearest the message. The closest always goes in. The best passage of each other source about as relevant goes in ahead of the rest, in up to half of what a reply carries, so a long website cannot crowd out a short policy; after that, no one source takes more than half while another has something about as relevant. Where two disagree, the reply follows the higher one — rules, then uploaded files, then single links, then pages read from a whole site — and never contradicts the business’s own documents. That order settles disagreements only: a reply answers from the passage that answers the question, and says what another organisation’s page says as theirs. Every reply then says what it relied on: sources, on the POST /v1/developer/drafts answer and on GET /v1/developer/drafts/{draftId}, lists the passages it was given — rules first — with the source, the page range or section, an excerpt of the passage’s own text, and a SHA-256 of the stored passage (with carried_chars when only its start fit).
Held replies
A reply with held_for_review: true was held by SlyOS’s checks for a person to read first — money, health or dosing, a legal or data-protection matter, another sensitive subject, or something the reply gives out that the account has not sent before — and hold_reasons says which. Do not send it automatically. null means SlyOS can no longer say, and is held; so is a missing field. Every answer that carries a reply carries the hold: the first POST /v1/developer/drafts answer, a replay of it, GET /v1/developer/drafts/{draftId}, and the draft.ready webhook.
Errors
Every refusal has one shape, whatever the status: { "code": "…", "message": "…" }. Branch on code; show message to a person. A 402 insufficient_funds also carries available_cents and needed_cents; a 429 sandbox_daily_limit carries used_today and daily_limit. Each operation lists its codes under the status it answers them with.
400 — the request is malformed. Fix it; retrying the same request will not help.401 — the key is not valid. 403 — the key is valid but lacks the scope.402 — out of API credit. Not an outage: the message is stored and can be answered by hand.404 — no such object for this key.409 — a settled state, not a fault (for example, somebody asked whether they are talking to a person). Do not retry — except generation_in_progress, not_stored, which the operations that answer them say are safe to retry with the same request.429 — over the rate limit, on an operation that lists rate_limited. Wait and retry.503 — SlyOS cannot reach a model provider. Retry with backoff; nothing was charged.
Limits
Each operation states its rate limit in requests a minute; one that lists 429 rate_limited refuses past it. A message body is at most 32,000 characters.
Webhooks
SlyOS can post events to an endpoint the account owner sets on the Developer screen — one for sandbox and one for live, each with its own signing secret; a live endpoint must be HTTPS (see webhooks). Every delivery is signed in the SlyOS-Signature header; verify it before trusting the body. Delivery is at least once: an endpoint that does not answer 2xx within ten seconds is tried again, up to 8 attempts over about 62 minutes, under the same event id — deduplicate on it. A redirect is not followed: it counts as a failed attempt.
Versioning
The version is in the path (/v1). Within a version, responses may gain fields: ignore fields you do not recognise.
Drafts
POST/v1/developer/drafts
Ask for a reply
Ask SlyOS to write a reply, using the account’s Brain, voice and history. The one billable call: 10¢ per successful response, charged once per generation_id.
Scope drafts:generate10¢ per AI response on a live key300 requests a minute
The reply is written by the account’s own Brain — what the business has taught SlyOS, the voice it has learned for the channel, and the conversation so far — through the same pipeline as the SlyOS inbox.
The only call that costs anything, and only on a live key. A request that does not produce a reply — refused, failed, or not needed — is not charged.
Check held_for_review before you send — on a replay too, which carries the hold the reply was written with. Send automatically only on false; true or null goes to a person, never straight to your customer, with hold_reasons saying why.
A replay (already_charged: true) is a reply SlyOS already gave you once. If your first request may have sent it, do not send it again: check your own record of what went out.
curl -X POST "https://api.slyos.world/v1/developer/drafts" \
-H "Authorization: Bearer $SLYOS_KEY" \
-H "Content-Type: application/json" \
-d '{
"generation_id": "9b2e4f71-3c8a-4d5e-a1f6-2e7b9c0d4a18:reply-1",
"message_id": "9b2e4f71-3c8a-4d5e-a1f6-2e7b9c0d4a18"
}'
Request body
- generation_idstring · required
- Your id for this one reply, and the idempotency key for the charge: sending the same
generation_id again does not buy a second reply. It is yours alone — unique within your account and the key’s environment, never shared with another account. Make it unique and reproducible — derive it from the message_id SlyOS gave you, e.g. <message_id>:reply-1, and use :reply-2 for a deliberate second reply. An id already used for a different conversation is refused (409 generation_id_conflict), never answered with that conversation’s reply.8–128 characters - card_idstring (uuid)
- The card to reply on. Give this or
message_id. - message_idstring (uuid)
- A
message_id from POST /v1/developer/messages. SlyOS replies on the card that message opened. Give this or card_id. - instructionstring
- A one-off steer for this reply, in plain words — for example “Offer a call on Thursday.” At most 2,000 characters.at most 2,000 characters
201 response
A reply was written for this generation_id.
- draft_idstring (uuid) · required
- The draft’s id.
GET /v1/developer/drafts/{draftId} reads it back. - card_idstring (uuid) · required
- The card the reply is for.
- generationinteger · required
- Which draft this is on the card: 1 for the first, higher after another reply was asked for.
- bodystring · required
- The reply text.
- held_for_reviewboolean | null · required
- True when SlyOS’s checks held this reply for a person — money, health or dosing, a legal or data-protection matter, another sensitive subject, or something it gives out that the account has not sent before. Never send a held reply automatically: show it to a person first. Null when SlyOS can no longer say, because the conversation has had a newer reply since; null means held. Send automatically only on
false. - hold_reasonsarray of object · required
- Why it was held: one entry per check that held it. Empty when
held_for_review is not true. - hold_reasons[].codestring · required
- Which check held it:
sensitive (money, legal, health or credentials), attachment (it carries a file), group (it goes to a group), regex_floor (it matches a rule you set), outbound_screen (it gives out something not sent before, or answers a risky request). A code not listed here is still a hold — treat every code you do not recognise as one. - hold_reasons[].labelstring · required
- The same reason in words, as the SlyOS inbox shows it.
- hold_detailstring | null · required
- What the checks found, in sentences, when the reply was held. Null when it was not held, or when SlyOS cannot say.
- billed_centsinteger · required
- What THIS request was charged: the price on a live key’s first success, 0 on a replay and in the sandbox.
- already_chargedboolean · required
- True when this
generation_id had already been paid for and this response is that same reply again. - originally_billed_centsinteger
- Only on a replay: what the original generation was charged.
- price_versionstring | null · required
- The price version the charge was made under. Null in the sandbox.
- environmentstring · required
- The environment of the key that made the call:
sandbox or live.one of: sandbox, live - replayedboolean · required
- True when this answer is a reply SlyOS already wrote for this
generation_id — in the sandbox too, where nothing is charged. It may already have been sent: do not send it again automatically. - generation_idstring · required
- The
generation_id you sent, echoed. - sourcesarray of object · required
- What this reply relied on: every passage of the business’s own knowledge — the links, sites and files it handed SlyOS, and its rules — that the reply was given, rules first. Empty when the reply was given none: the business has handed SlyOS nothing yet, or nothing it handed over matched.
- sources[].source_idstring (uuid) | null · required
- The knowledge source the passage came from. Null once that source is deleted.
- sources[].passage_idstring (uuid) | null · required
- The passage itself. Null once its source is deleted.
- sources[].titlestring | null · required
- What the source was called when the reply was written: its title, file name or address.
- sources[].urlstring | null · required
- The page the passage was read from, for a link or a site.
- sources[].pageinteger | null · required
- The page of the file its own text starts on, for a file that has pages. With
page_end, the range it covers. - sources[].page_endinteger | null · required
- The last page it runs onto, when it runs past
page — a passage starting on page 11 and carrying page 12 is page: 11, page_end: 12 (p.11–12). Null when it stays on one page, or the file has no pages. - sources[].sectionstring | null · required
- The heading it sat under, if any.
- sources[].ruleboolean · required
- True for a binding rule the reply had to follow; false for reference material it could draw on.
- sources[].rankinteger · required
- Its place in what the reply was given, from 1 — counted separately for rules and for reference.
- sources[].scorenumber | null · required
- How close the passage was to the message, as cosine similarity. Null when there was nothing to compare.
- sources[].excerptstring | null · required
- Up to 280 characters of the passage’s OWN text — past the lines it repeats from the passage before it — from the sentence that shares the most words with the reply, else from its start;
… marks a cut. While its source still exists. - sources[].text_sha256string · required
- SHA-256 of the stored passage the reply was given — all of it, or its first
carried_chars characters: proof of which text it relied on, even after the source changes. - sources[].carried_charsinteger | null · required
- How many of the passage’s characters the reply was given, when it was cut to fit. Null when it was given the whole passage.
{
"draft_id": "e1f7a3c5-9d2b-4e68-b0a4-6c3e8f1d2a97",
"card_id": "5e8d1c3a-7f24-4b9e-8c61-0a3f9d2e7b14",
"generation": 1,
"body": "Hi Dana — yes, we ship to Canada. Orders usually arrive within 5–8 business days, and you’ll get a tracking link by email as soon as yours leaves our warehouse.",
"held_for_review": false,
"hold_reasons": [],
"hold_detail": null,
"billed_cents": 10,
"already_charged": false,
"price_version": "2026-09-01",
"environment": "live",
"replayed": false,
"generation_id": "9b2e4f71-3c8a-4d5e-a1f6-2e7b9c0d4a18:reply-1",
"sources": [
{
"source_id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"passage_id": "2f9e4c1a-7b3d-4e8f-a5c2-6d1b9e3f7a40",
"title": "Example Co — website",
"url": "https://www.example.com/shipping",
"page": null,
"page_end": null,
"section": "Shipping",
"rule": false,
"rank": 1,
"score": 0.83,
"excerpt": "We ship to the US and Canada. Orders leave our warehouse within two business days.",
"text_sha256": "3b7e1f9a2c4d6e8f0a1b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e2f",
"carried_chars": null
}
]
}
200 response
A live key sent a generation_id that was already paid for: the same reply again, with the hold it was written with, charged nothing. It may already have been sent — do not send it again automatically. The same fields as the 201 response.
{
"draft_id": "e1f7a3c5-9d2b-4e68-b0a4-6c3e8f1d2a97",
"card_id": "5e8d1c3a-7f24-4b9e-8c61-0a3f9d2e7b14",
"generation": 1,
"body": "Hi Dana — yes, we ship to Canada. Orders usually arrive within 5–8 business days, and you’ll get a tracking link by email as soon as yours leaves our warehouse.",
"held_for_review": false,
"hold_reasons": [],
"hold_detail": null,
"billed_cents": 0,
"already_charged": true,
"originally_billed_cents": 10,
"price_version": "2026-09-01",
"environment": "live",
"replayed": true,
"generation_id": "9b2e4f71-3c8a-4d5e-a1f6-2e7b9c0d4a18:reply-1",
"sources": [
{
"source_id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"passage_id": "2f9e4c1a-7b3d-4e8f-a5c2-6d1b9e3f7a40",
"title": "Example Co — website",
"url": "https://www.example.com/shipping",
"page": null,
"page_end": null,
"section": "Shipping",
"rule": false,
"rank": 1,
"score": 0.83,
"excerpt": "We ship to the US and Canada. Orders leave our warehouse within two business days.",
"text_sha256": "3b7e1f9a2c4d6e8f0a1b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e2f",
"carried_chars": null
}
]
}
Errors
- bad_request400
- The payload is malformed — a generation_id shorter than 8 or longer than 128 characters, an id that is not a UUID — or neither card_id nor message_id was given, or they name two different conversations.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- insufficient_funds402
- No API credit remains. The message is still stored and visible, and can be answered by hand. Nothing was charged.
- missing_scope403
- The key does not carry drafts:generate.
- not_found404
- No such message or card in this key’s environment. A sandbox key cannot reach a live card, and neither can reach another channel’s.
- no_card409
- That message needs no reply, so there is nothing to draft.
- channel_paused409
- The channel is paused on the Developer screen, so nothing is drafted on it. Nothing was charged.
- generation_in_progress409
- Another request with this generation_id is still being drafted. Retry after Retry-After with the same id to get that draft, charged once.
- generation_id_conflict409
- That generation_id is already taken on this account. Nothing was charged.
- draft_gone409
- The reply this generation_id produced was deleted with its conversation. Use a new generation_id.
- paused_identity409
- Someone asked whether they are talking to a person; drafting is paused until the account owner clears it. Nothing was charged.
- paused_allowance409
- Sandbox only: the plan’s AI allowance is used up, and sandbox drafts are drawn from the plan. Live drafts are paid from the wallet and never refused for this. Nothing was charged.
- filed_away409
- The account owner archived or filed the conversation. Do not retry. Nothing was charged.
- no_reply_needed409
- The model judged nobody is waiting for a reply (an automated message, say), so no draft was written. Nothing was charged.
- refused409
- No draft could be produced for that card: its conversation or its channel could not be used. A card_id that does not exist is a 404
not_found, not this. Nothing was charged. - ai_off409
- The account owner has not allowed SlyOS to send their data to AI providers. Nothing was sent or charged. Do not retry until they allow it in the app.
- too_large413
- The request body is larger than this endpoint accepts.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key, sandbox included. Wait a minute.
- sandbox_daily_limit429
- Sandbox only: this account has had 50 sandbox drafts in the last 24 hours. Retry after Retry-After, or use a live key. A replay of a draft already written is not counted. Nothing was charged.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
- outage503
- No model provider is reachable. Retry after Retry-After with the same generation_id. Nothing was charged.
- try_again503
- The draft could not be charged for in time, so it was not. Retry with the same generation_id.
- drafting_unavailable503
- Drafting is not configured on this deployment.
GET/v1/developer/drafts/{draftId}
Read a reply back
Read a draft back. Free.
Scope drafts:readFree600 requests a minute
curl "https://api.slyos.world/v1/developer/drafts/$DRAFT_ID" \
-H "Authorization: Bearer $SLYOS_KEY"
Parameters
- draftIdstring (uuid) · in path · required
- The
draft_id to read, from POST /v1/developer/drafts or draft.ready.
200 response
The draft exists on this account.
- draft_idstring (uuid) · required
- The draft’s id.
- card_idstring (uuid) · required
- The card the reply is for.
- bodystring · required
- The reply text.
- generationinteger · required
- Which draft this is on the card.
- modelstring · required
- The model that wrote it.
- created_atstring (date-time) · required
- When it was written.
- held_for_reviewboolean | null · required
- True when SlyOS’s checks held this reply for a person — money, health or dosing, a legal or data-protection matter, another sensitive subject, or something it gives out that the account has not sent before. Never send a held reply automatically: show it to a person first. Null when SlyOS can no longer say, because the conversation has had a newer reply since; null means held. Send automatically only on
false. - hold_reasonsarray of object · required
- Why it was held: one entry per check that held it. Empty when
held_for_review is not true. - hold_reasons[].codestring · required
- Which check held it:
sensitive (money, legal, health or credentials), attachment (it carries a file), group (it goes to a group), regex_floor (it matches a rule you set), outbound_screen (it gives out something not sent before, or answers a risky request). A code not listed here is still a hold — treat every code you do not recognise as one. - hold_reasons[].labelstring · required
- The same reason in words, as the SlyOS inbox shows it.
- hold_detailstring | null · required
- What the checks found, in sentences, when the reply was held. Null when it was not held, or when SlyOS cannot say.
- supersededboolean · required
- True when a newer reply has since been written on the same card. Send the newest, not this one.
- sourcesarray of object · required
- What this reply relied on: every passage of the business’s own knowledge — the links, sites and files it handed SlyOS, and its rules — that the reply was given, rules first. Empty when the reply was given none: the business has handed SlyOS nothing yet, or nothing it handed over matched.
- sources[].source_idstring (uuid) | null · required
- The knowledge source the passage came from. Null once that source is deleted.
- sources[].passage_idstring (uuid) | null · required
- The passage itself. Null once its source is deleted.
- sources[].titlestring | null · required
- What the source was called when the reply was written: its title, file name or address.
- sources[].urlstring | null · required
- The page the passage was read from, for a link or a site.
- sources[].pageinteger | null · required
- The page of the file its own text starts on, for a file that has pages. With
page_end, the range it covers. - sources[].page_endinteger | null · required
- The last page it runs onto, when it runs past
page — a passage starting on page 11 and carrying page 12 is page: 11, page_end: 12 (p.11–12). Null when it stays on one page, or the file has no pages. - sources[].sectionstring | null · required
- The heading it sat under, if any.
- sources[].ruleboolean · required
- True for a binding rule the reply had to follow; false for reference material it could draw on.
- sources[].rankinteger · required
- Its place in what the reply was given, from 1 — counted separately for rules and for reference.
- sources[].scorenumber | null · required
- How close the passage was to the message, as cosine similarity. Null when there was nothing to compare.
- sources[].excerptstring | null · required
- Up to 280 characters of the passage’s OWN text — past the lines it repeats from the passage before it — from the sentence that shares the most words with the reply, else from its start;
… marks a cut. While its source still exists. - sources[].text_sha256string · required
- SHA-256 of the stored passage the reply was given — all of it, or its first
carried_chars characters: proof of which text it relied on, even after the source changes. - sources[].carried_charsinteger | null · required
- How many of the passage’s characters the reply was given, when it was cut to fit. Null when it was given the whole passage.
{
"draft_id": "e1f7a3c5-9d2b-4e68-b0a4-6c3e8f1d2a97",
"card_id": "5e8d1c3a-7f24-4b9e-8c61-0a3f9d2e7b14",
"body": "Hi Dana — yes, we ship to Canada. Orders usually arrive within 5–8 business days, and you’ll get a tracking link by email as soon as yours leaves our warehouse.",
"generation": 1,
"model": "claude-opus-5-5",
"created_at": "2026-10-09T15:42:11.000Z",
"held_for_review": false,
"hold_reasons": [],
"hold_detail": null,
"superseded": false,
"sources": [
{
"source_id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"passage_id": "2f9e4c1a-7b3d-4e8f-a5c2-6d1b9e3f7a40",
"title": "Example Co — website",
"url": "https://www.example.com/shipping",
"page": null,
"page_end": null,
"section": "Shipping",
"rule": false,
"rank": 1,
"score": 0.83,
"excerpt": "We ship to the US and Canada. Orders leave our warehouse within two business days.",
"text_sha256": "3b7e1f9a2c4d6e8f0a1b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e2f",
"carried_chars": null
}
]
}
Errors
- bad_request400
- The draft id is not a UUID.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry drafts:read.
- not_found404
- No such draft in this key’s environment.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key, sandbox included. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
Knowledge
POST/v1/developer/knowledge/sources
Add a link, a site or a file
Add a source: JSON {url, crawl?, rules?, title?, scope?} for a page or a whole site, or multipart with a `file` (PDF, Word, text, Markdown, CSV; up to 25 MB). Answers 202; the source is read in the background. Needs a live key.
Scope brain:writeFree60 requests a minute
A link or a site is JSON: {"url": "…"}, with "crawl": true to read the whole site. A file is multipart/form-data with the file in a file field.
Mark terms, policies and regulations rules: replies must follow a rule, and draw on everything else as reference.
As application/json
curl -X POST "https://api.slyos.world/v1/developer/knowledge/sources" \
-H "Authorization: Bearer $SLYOS_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.example.com/",
"crawl": true
}'
As multipart/form-data
curl -X POST "https://api.slyos.world/v1/developer/knowledge/sources" \
-H "Authorization: Bearer $SLYOS_KEY" \
-F 'file=@returns-policy.pdf' \
-F 'rules=true' \
-F 'title=Returns policy'
Request body — application/json
- urlstring · required
- A public http(s) address: one page — your pricing page, a policy, a regulation — or, with
crawl, the start of a whole site.1–2,048 characters - crawlboolean
- Read the whole site from this address: the same site only, robots.txt respected, up to the page limit this operation states. Default: this page alone.
- rulesboolean
- True when replies must FOLLOW this source — terms, a policy, a regulation — rather than draw on it as reference. Default false.
- titlestring
- What to call it on the Developer screen and in a reply’s
sources.at most 300 characters - scopestring
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account
Request body — multipart/form-data
- filestring (binary) · required
- The file — PDF, Word (.docx), plain text, Markdown or CSV, up to the size this operation states. It is read to the end; a long one is cut into passages, not cut short.
- rulesstring
true when replies must follow this file rather than draw on it. Default false.one of: true, false- titlestring
- What to call it on the Developer screen and in a reply’s
sources. - scopestring
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account
202 response
Taken in. It is read in the background: poll GET /v1/developer/knowledge/sources/{sourceId} until status is ready.
- idstring (uuid) · required
- The source’s id.
- kindstring · required
link: one page. site: a whole site, read from one address. file: an upload.one of: link, site, file- urlstring | null · required
- The address it is read from. Null for a file.
- filenamestring | null · required
- The uploaded file’s name. Null for a link or a site.
- titlestring | null · required
- What it is called on the Developer screen and in a reply’s
sources. - rulesboolean · required
- True when replies must follow it; false when it is reference material.
- scopestring · required
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account- statusstring · required
queued, then processing, while it is read in the background; ready once replies use it; failed when it could not be read, with status_reason saying why.one of: queued, processing, ready, failed- status_reasonstring | null · required
- In a sentence, why the status is what it is. Null when there is nothing to say.
- warningstring | null · required
- Set when the source is
ready but some of what it shows may be missing, in a sentence naming the pages and what to do — today, pages that build their content with JavaScript, which SlyOS does not run (a price list drawn from a script, a template filled in after the page loads). Null when there is nothing to warn about. - incomplete_pagesarray of string · required
- The addresses of the pages
warning names: pages whose content is built with JavaScript, so replies may be missing what a visitor sees there. Add that text as a file, or as a single link to a page that shows it. Empty when there are none. - pagesinteger · required
- Pages read from it.
- passagesinteger · required
- Passages it was cut into: what a reply retrieves from.
- charactersinteger · required
- Characters of text read from it.
- size_bytesinteger | null · required
- The uploaded file’s size. Null for a link or a site.
- content_sha256string | null · required
- SHA-256 of the text read from it; it changes when a refresh reads something new.
- file_sha256string | null · required
- SHA-256 of the uploaded file’s bytes. Null for a link or a site.
- used_in_repliesinteger · required
- How many replies have relied on a passage of it.
- rules_fitboolean | null · required
- For a rules source: true when every one of the business’s rules reaches every reply; false when they no longer fit in one reply, and each reply gets the rules nearest its message. Null for reference material, or when it was not measured.
- rules_notestring | null · required
- When
rules_fit is false, in a sentence: how much the rules come to, what one reply carries, and what to do about it. - created_atstring (date-time) · required
- When it was added.
- updated_atstring (date-time) · required
- When it last changed.
- fetched_atstring (date-time) | null · required
- When it was last read. Null until it has been.
- duplicateboolean · required
- True when this address or this exact file was already a source: nothing new was added, and this is that source.
{
"id": "0e7c2a9d-5f1b-4d38-a6e4-9b3c1f7d2a85",
"kind": "file",
"url": null,
"filename": "returns-policy.pdf",
"title": "Returns policy",
"rules": true,
"scope": "project",
"status": "queued",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 0,
"passages": 0,
"characters": 0,
"size_bytes": 284311,
"content_sha256": null,
"file_sha256": "9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c",
"used_in_replies": 0,
"rules_fit": true,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:20:04.000Z",
"fetched_at": null,
"duplicate": false
}
200 response
That address, or that exact file, is already a source: this is it, and nothing new was added. The same fields as the 202 response.
{
"id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"kind": "site",
"url": "https://www.example.com/",
"filename": null,
"title": "Example Co — website",
"rules": false,
"scope": "project",
"status": "ready",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 24,
"passages": 187,
"characters": 96412,
"size_bytes": null,
"content_sha256": "4f2a9c0e7b1d3e5f6a8c9b0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f",
"file_sha256": null,
"used_in_replies": 38,
"rules_fit": null,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:21:37.000Z",
"fetched_at": "2026-10-09T15:21:37.000Z",
"duplicate": true
}
Errors
- bad_request400
- No url and no file, or an address SlyOS will not read.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:write.
- sandbox_read_only403
- A sandbox key can read knowledge but not change it.
- too_many_sources409
- The account already holds the most knowledge sources it may.
- knowledge_full409
- The account already holds the most knowledge text it may.
- too_large413
- The request body is larger than this endpoint accepts.
- unsupported_type422
- Not a file type SlyOS reads (PDF, Word .docx, plain text, Markdown, CSV).
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- busy429
- Too many sources are being read at once. Add more when they finish.
- uploads_busy429
- Two files are already uploading for this account. Send the next after.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
GET/v1/developer/knowledge/sources
List knowledge sources
The sources this key’s replies use — its project’s and the account’s — with status. Free.
Scope brain:readFree240 requests a minute
curl "https://api.slyos.world/v1/developer/knowledge/sources" \
-H "Authorization: Bearer $SLYOS_KEY"
200 response
Always, for a valid key.
- sourcesarray of object · required
- Every source this key’s replies use: its project’s and the account’s.
- sources[].idstring (uuid) · required
- The source’s id.
- sources[].kindstring · required
link: one page. site: a whole site, read from one address. file: an upload.one of: link, site, file- sources[].urlstring | null · required
- The address it is read from. Null for a file.
- sources[].filenamestring | null · required
- The uploaded file’s name. Null for a link or a site.
- sources[].titlestring | null · required
- What it is called on the Developer screen and in a reply’s
sources. - sources[].rulesboolean · required
- True when replies must follow it; false when it is reference material.
- sources[].scopestring · required
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account- sources[].statusstring · required
queued, then processing, while it is read in the background; ready once replies use it; failed when it could not be read, with status_reason saying why.one of: queued, processing, ready, failed- sources[].status_reasonstring | null · required
- In a sentence, why the status is what it is. Null when there is nothing to say.
- sources[].warningstring | null · required
- Set when the source is
ready but some of what it shows may be missing, in a sentence naming the pages and what to do — today, pages that build their content with JavaScript, which SlyOS does not run (a price list drawn from a script, a template filled in after the page loads). Null when there is nothing to warn about. - sources[].incomplete_pagesarray of string · required
- The addresses of the pages
warning names: pages whose content is built with JavaScript, so replies may be missing what a visitor sees there. Add that text as a file, or as a single link to a page that shows it. Empty when there are none. - sources[].pagesinteger · required
- Pages read from it.
- sources[].passagesinteger · required
- Passages it was cut into: what a reply retrieves from.
- sources[].charactersinteger · required
- Characters of text read from it.
- sources[].size_bytesinteger | null · required
- The uploaded file’s size. Null for a link or a site.
- sources[].content_sha256string | null · required
- SHA-256 of the text read from it; it changes when a refresh reads something new.
- sources[].file_sha256string | null · required
- SHA-256 of the uploaded file’s bytes. Null for a link or a site.
- sources[].used_in_repliesinteger · required
- How many replies have relied on a passage of it.
- sources[].rules_fitboolean | null · required
- For a rules source: true when every one of the business’s rules reaches every reply; false when they no longer fit in one reply, and each reply gets the rules nearest its message. Null for reference material, or when it was not measured.
- sources[].rules_notestring | null · required
- When
rules_fit is false, in a sentence: how much the rules come to, what one reply carries, and what to do about it. - sources[].created_atstring (date-time) · required
- When it was added.
- sources[].updated_atstring (date-time) · required
- When it last changed.
- sources[].fetched_atstring (date-time) | null · required
- When it was last read. Null until it has been.
{
"sources": [
{
"id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"kind": "site",
"url": "https://www.example.com/",
"filename": null,
"title": "Example Co — website",
"rules": false,
"scope": "project",
"status": "ready",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 24,
"passages": 187,
"characters": 96412,
"size_bytes": null,
"content_sha256": "4f2a9c0e7b1d3e5f6a8c9b0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f",
"file_sha256": null,
"used_in_replies": 38,
"rules_fit": null,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:21:37.000Z",
"fetched_at": "2026-10-09T15:21:37.000Z"
}
]
}
Errors
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:read.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
GET/v1/developer/knowledge/sources/{sourceId}
Read a knowledge source
One source: status and why, pages and passages read, and how many replies relied on it. Free.
Scope brain:readFree240 requests a minute
curl "https://api.slyos.world/v1/developer/knowledge/sources/$SOURCE_ID" \
-H "Authorization: Bearer $SLYOS_KEY"
Parameters
- sourceIdstring (uuid) · in path · required
- A knowledge source’s
id, from adding it or listing them.
200 response
The source exists for this key.
- idstring (uuid) · required
- The source’s id.
- kindstring · required
link: one page. site: a whole site, read from one address. file: an upload.one of: link, site, file- urlstring | null · required
- The address it is read from. Null for a file.
- filenamestring | null · required
- The uploaded file’s name. Null for a link or a site.
- titlestring | null · required
- What it is called on the Developer screen and in a reply’s
sources. - rulesboolean · required
- True when replies must follow it; false when it is reference material.
- scopestring · required
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account- statusstring · required
queued, then processing, while it is read in the background; ready once replies use it; failed when it could not be read, with status_reason saying why.one of: queued, processing, ready, failed- status_reasonstring | null · required
- In a sentence, why the status is what it is. Null when there is nothing to say.
- warningstring | null · required
- Set when the source is
ready but some of what it shows may be missing, in a sentence naming the pages and what to do — today, pages that build their content with JavaScript, which SlyOS does not run (a price list drawn from a script, a template filled in after the page loads). Null when there is nothing to warn about. - incomplete_pagesarray of string · required
- The addresses of the pages
warning names: pages whose content is built with JavaScript, so replies may be missing what a visitor sees there. Add that text as a file, or as a single link to a page that shows it. Empty when there are none. - pagesinteger · required
- Pages read from it.
- passagesinteger · required
- Passages it was cut into: what a reply retrieves from.
- charactersinteger · required
- Characters of text read from it.
- size_bytesinteger | null · required
- The uploaded file’s size. Null for a link or a site.
- content_sha256string | null · required
- SHA-256 of the text read from it; it changes when a refresh reads something new.
- file_sha256string | null · required
- SHA-256 of the uploaded file’s bytes. Null for a link or a site.
- used_in_repliesinteger · required
- How many replies have relied on a passage of it.
- rules_fitboolean | null · required
- For a rules source: true when every one of the business’s rules reaches every reply; false when they no longer fit in one reply, and each reply gets the rules nearest its message. Null for reference material, or when it was not measured.
- rules_notestring | null · required
- When
rules_fit is false, in a sentence: how much the rules come to, what one reply carries, and what to do about it. - created_atstring (date-time) · required
- When it was added.
- updated_atstring (date-time) · required
- When it last changed.
- fetched_atstring (date-time) | null · required
- When it was last read. Null until it has been.
{
"id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"kind": "site",
"url": "https://www.example.com/",
"filename": null,
"title": "Example Co — website",
"rules": false,
"scope": "project",
"status": "ready",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 24,
"passages": 187,
"characters": 96412,
"size_bytes": null,
"content_sha256": "4f2a9c0e7b1d3e5f6a8c9b0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f",
"file_sha256": null,
"used_in_replies": 38,
"rules_fit": null,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:21:37.000Z",
"fetched_at": "2026-10-09T15:21:37.000Z"
}
Errors
- bad_request400
- The source id is not a UUID.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:read.
- not_found404
- No such source for this key.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
PATCH/v1/developer/knowledge/sources/{sourceId}
Mark a source as rules, or rename it
Mark a source as binding rules or as reference material, or rename it.
Scope brain:writeFree60 requests a minute
curl -X PATCH "https://api.slyos.world/v1/developer/knowledge/sources/$SOURCE_ID" \
-H "Authorization: Bearer $SLYOS_KEY" \
-H "Content-Type: application/json" \
-d '{
"rules": true
}'
Parameters
- sourceIdstring (uuid) · in path · required
- A knowledge source’s
id, from adding it or listing them.
Request body
- rulesboolean
- True to make it a binding rule; false to make it reference material.
- titlestring | null
- A new name for it; null to go back to the name it was read with.at most 300 characters
200 response
Changed. The next reply uses it as changed.
- idstring (uuid) · required
- The source’s id.
- kindstring · required
link: one page. site: a whole site, read from one address. file: an upload.one of: link, site, file- urlstring | null · required
- The address it is read from. Null for a file.
- filenamestring | null · required
- The uploaded file’s name. Null for a link or a site.
- titlestring | null · required
- What it is called on the Developer screen and in a reply’s
sources. - rulesboolean · required
- True when replies must follow it; false when it is reference material.
- scopestring · required
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account- statusstring · required
queued, then processing, while it is read in the background; ready once replies use it; failed when it could not be read, with status_reason saying why.one of: queued, processing, ready, failed- status_reasonstring | null · required
- In a sentence, why the status is what it is. Null when there is nothing to say.
- warningstring | null · required
- Set when the source is
ready but some of what it shows may be missing, in a sentence naming the pages and what to do — today, pages that build their content with JavaScript, which SlyOS does not run (a price list drawn from a script, a template filled in after the page loads). Null when there is nothing to warn about. - incomplete_pagesarray of string · required
- The addresses of the pages
warning names: pages whose content is built with JavaScript, so replies may be missing what a visitor sees there. Add that text as a file, or as a single link to a page that shows it. Empty when there are none. - pagesinteger · required
- Pages read from it.
- passagesinteger · required
- Passages it was cut into: what a reply retrieves from.
- charactersinteger · required
- Characters of text read from it.
- size_bytesinteger | null · required
- The uploaded file’s size. Null for a link or a site.
- content_sha256string | null · required
- SHA-256 of the text read from it; it changes when a refresh reads something new.
- file_sha256string | null · required
- SHA-256 of the uploaded file’s bytes. Null for a link or a site.
- used_in_repliesinteger · required
- How many replies have relied on a passage of it.
- rules_fitboolean | null · required
- For a rules source: true when every one of the business’s rules reaches every reply; false when they no longer fit in one reply, and each reply gets the rules nearest its message. Null for reference material, or when it was not measured.
- rules_notestring | null · required
- When
rules_fit is false, in a sentence: how much the rules come to, what one reply carries, and what to do about it. - created_atstring (date-time) · required
- When it was added.
- updated_atstring (date-time) · required
- When it last changed.
- fetched_atstring (date-time) | null · required
- When it was last read. Null until it has been.
{
"id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"kind": "site",
"url": "https://www.example.com/",
"filename": null,
"title": "Example Co — website",
"rules": true,
"scope": "project",
"status": "ready",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 24,
"passages": 187,
"characters": 96412,
"size_bytes": null,
"content_sha256": "4f2a9c0e7b1d3e5f6a8c9b0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f",
"file_sha256": null,
"used_in_replies": 38,
"rules_fit": true,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:21:37.000Z",
"fetched_at": "2026-10-09T15:21:37.000Z"
}
Errors
- bad_request400
- The source id is not a UUID, or the body is malformed: nothing to change (send rules or title), or a title over 300 characters.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:write.
- sandbox_read_only403
- A sandbox key can read knowledge but not change it.
- not_found404
- No such source for this key.
- too_large413
- The request body is larger than this endpoint accepts.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
DELETE/v1/developer/knowledge/sources/{sourceId}
Delete a source
Delete a source and every passage read from it. Replies stop using it at once.
Scope brain:writeFree60 requests a minute
curl -X DELETE "https://api.slyos.world/v1/developer/knowledge/sources/$SOURCE_ID" \
-H "Authorization: Bearer $SLYOS_KEY"
Parameters
- sourceIdstring (uuid) · in path · required
- A knowledge source’s
id, from adding it or listing them.
200 response
Deleted, with every passage read from it. No reply uses it from now on.
- idstring (uuid) · required
- The source that was deleted.
- deletedtrue · required
- Always true on a 200.
{
"id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"deleted": true
}
Errors
- bad_request400
- The source id is not a UUID.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:write.
- sandbox_read_only403
- A sandbox key can read knowledge but not change it.
- not_found404
- No such source for this key.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
GET/v1/developer/knowledge/sources/{sourceId}/passages
Read what was taken from a source
The passages read from a source, in order, with page, section and URL: exactly what replies retrieve from. Free.
Scope brain:readFree120 requests a minute
Exactly the passages replies retrieve from — check here what SlyOS read.
curl "https://api.slyos.world/v1/developer/knowledge/sources/$SOURCE_ID/passages" \
-H "Authorization: Bearer $SLYOS_KEY"
Parameters
- sourceIdstring (uuid) · in path · required
- A knowledge source’s
id, from adding it or listing them. - limitinteger · in query
- How many passages to return.default: 50 · at least 1 · at most 200
- afterinteger · in query
- Return passages after this
ordinal: the previous page’s next_after.default: -1
200 response
The source exists for this key.
- source_idstring (uuid) · required
- The source the passages belong to.
- passagesarray of object · required
- The passages, in order.
- passages[].idstring (uuid) · required
- The passage’s id: a reply’s
sources[].passage_id. - passages[].ordinalinteger · required
- Its place in the source, from 0.
- passages[].pageinteger | null · required
- The page of the file its own text starts on, if the file has pages.
- passages[].page_endinteger | null · required
- The last page it runs onto, when it runs past
page. Null when it stays on one page, the file has no pages, or it was read before page ranges were recorded. - passages[].sectionstring | null · required
- The heading it sits under, if any.
- passages[].urlstring | null · required
- The page of a site it was read from.
- passages[].textstring · required
- The passage, exactly as replies are given it.
- next_afterinteger | null · required
- Pass as
after for the next page. Null on the last page.
{
"source_id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"passages": [
{
"id": "2f9e4c1a-7b3d-4e8f-a5c2-6d1b9e3f7a40",
"ordinal": 0,
"page": null,
"page_end": null,
"section": "Shipping",
"url": "https://www.example.com/shipping",
"text": "We ship to the US and Canada. Orders leave our warehouse within two business days."
}
],
"next_after": null
}
Errors
- bad_request400
- The source id is not a UUID, or limit is not 1 to 200, or after is not a whole number from -1.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:read.
- not_found404
- No such source for this key.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
POST/v1/developer/knowledge/sources/{sourceId}/refresh
Read a link or a site again
Read a link or a site again. The copy already read keeps answering until the new one is ready.
Scope brain:writeFree30 requests a minute
Refresh after your site or a regulation page changes; replies use the new text once it is ready.
curl -X POST "https://api.slyos.world/v1/developer/knowledge/sources/$SOURCE_ID/refresh" \
-H "Authorization: Bearer $SLYOS_KEY"
Parameters
- sourceIdstring (uuid) · in path · required
- A knowledge source’s
id, from adding it or listing them.
202 response
Queued. The copy already read keeps answering until the new one is ready.
- idstring (uuid) · required
- The source’s id.
- kindstring · required
link: one page. site: a whole site, read from one address. file: an upload.one of: link, site, file- urlstring | null · required
- The address it is read from. Null for a file.
- filenamestring | null · required
- The uploaded file’s name. Null for a link or a site.
- titlestring | null · required
- What it is called on the Developer screen and in a reply’s
sources. - rulesboolean · required
- True when replies must follow it; false when it is reference material.
- scopestring · required
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account- statusstring · required
queued, then processing, while it is read in the background; ready once replies use it; failed when it could not be read, with status_reason saying why.one of: queued, processing, ready, failed- status_reasonstring | null · required
- In a sentence, why the status is what it is. Null when there is nothing to say.
- warningstring | null · required
- Set when the source is
ready but some of what it shows may be missing, in a sentence naming the pages and what to do — today, pages that build their content with JavaScript, which SlyOS does not run (a price list drawn from a script, a template filled in after the page loads). Null when there is nothing to warn about. - incomplete_pagesarray of string · required
- The addresses of the pages
warning names: pages whose content is built with JavaScript, so replies may be missing what a visitor sees there. Add that text as a file, or as a single link to a page that shows it. Empty when there are none. - pagesinteger · required
- Pages read from it.
- passagesinteger · required
- Passages it was cut into: what a reply retrieves from.
- charactersinteger · required
- Characters of text read from it.
- size_bytesinteger | null · required
- The uploaded file’s size. Null for a link or a site.
- content_sha256string | null · required
- SHA-256 of the text read from it; it changes when a refresh reads something new.
- file_sha256string | null · required
- SHA-256 of the uploaded file’s bytes. Null for a link or a site.
- used_in_repliesinteger · required
- How many replies have relied on a passage of it.
- rules_fitboolean | null · required
- For a rules source: true when every one of the business’s rules reaches every reply; false when they no longer fit in one reply, and each reply gets the rules nearest its message. Null for reference material, or when it was not measured.
- rules_notestring | null · required
- When
rules_fit is false, in a sentence: how much the rules come to, what one reply carries, and what to do about it. - created_atstring (date-time) · required
- When it was added.
- updated_atstring (date-time) · required
- When it last changed.
- fetched_atstring (date-time) | null · required
- When it was last read. Null until it has been.
{
"id": "6b1d4f8a-3c2e-4a9f-b7d0-1e5c8a2f4d63",
"kind": "site",
"url": "https://www.example.com/",
"filename": null,
"title": "Example Co — website",
"rules": false,
"scope": "project",
"status": "queued",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 24,
"passages": 187,
"characters": 96412,
"size_bytes": null,
"content_sha256": "4f2a9c0e7b1d3e5f6a8c9b0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f",
"file_sha256": null,
"used_in_replies": 38,
"rules_fit": null,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:21:37.000Z",
"fetched_at": "2026-10-09T15:21:37.000Z"
}
Errors
- bad_request400
- The source id is not a UUID.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:write.
- sandbox_read_only403
- A sandbox key can read knowledge but not change it.
- not_found404
- No such source for this key.
- cannot_refresh409
- A file is read once and not kept. Upload the new version instead.
- busy409
- That source is being read right now.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
GET/v1/developer/knowledge/profile
Read the business profile
The business profile this key’s replies use: name, description, tone notes. Free.
Scope brain:readFree120 requests a minute
curl "https://api.slyos.world/v1/developer/knowledge/profile" \
-H "Authorization: Bearer $SLYOS_KEY"
200 response
Always, for a valid key.
- business_namestring | null · required
- The business’s name, as replies give it.
- descriptionstring | null · required
- What the business is and does, in its own words.
- tone_notesstring | null · required
- How replies should sound.
- use_personal_contextboolean · required
- Whether API replies also use everything SlyOS knows about the account owner: facts from their own conversations and the ones they told it, their past replies on their other channels, their documents, calendar and saved details, and their About you. On unless the owner turned it off on the Developer screen; a key cannot change it. Off, a reply still uses the owner’s name, rules and writing style. Either way, nothing one customer wrote or was sent goes into another customer’s reply, and nothing from a sandbox conversation goes into a live one; every reply the account sends still shapes its writing style.
- updated_atstring (date-time) | null · required
- When the profile last changed. Null if it never has.
{
"business_name": "Example Co",
"description": "We make and sell refillable kitchen goods online, shipping to the US and Canada. We do not take phone orders.",
"tone_notes": "Warm and brief. Sign off as “The Example Co team”.",
"use_personal_context": true,
"updated_at": "2026-10-09T15:18:52.000Z"
}
Errors
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:read.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
PUT/v1/developer/knowledge/profile
Say who the business is and how it sounds
Set what the business is and how it wants to sound. Used in every API reply of this key’s project.
Scope brain:writeFree30 requests a minute
A field you leave out is left as it was; null clears it. Whether replies use everything SlyOS knows about the owner (use_personal_context) is the owner’s switch, on the Developer screen: a key may send back the value GET answered, and a key that tries to change it is refused.
curl -X PUT "https://api.slyos.world/v1/developer/knowledge/profile" \
-H "Authorization: Bearer $SLYOS_KEY" \
-H "Content-Type: application/json" \
-d '{
"business_name": "Example Co",
"description": "We make and sell refillable kitchen goods online, shipping to the US and Canada. We do not take phone orders.",
"tone_notes": "Warm and brief. Sign off as “The Example Co team”."
}'
Request body
- business_namestring | null
- The business’s name, as replies should give it.at most 200 characters
- descriptionstring | null
- What the business is and does, in your own words: what it sells, who it serves, what it will and will not do.at most 8,000 characters
- tone_notesstring | null
- How replies should sound — formal or warm, how to sign off — on top of the voice SlyOS learns from your own replies.at most 2,000 characters
- use_personal_contextboolean
- Accepted only when it equals the stored value, so the object
GET returns can be sent back. A key that tries to change it, either way, is refused: only the account owner can, on the Developer screen. - updated_atstring | null
- Accepted and ignored, so the object
GET returns can be sent back.
200 response
Saved. Every reply asked for with this key’s project uses it from now on.
- business_namestring | null · required
- The business’s name, as replies give it.
- descriptionstring | null · required
- What the business is and does, in its own words.
- tone_notesstring | null · required
- How replies should sound.
- use_personal_contextboolean · required
- Whether API replies also use everything SlyOS knows about the account owner: facts from their own conversations and the ones they told it, their past replies on their other channels, their documents, calendar and saved details, and their About you. On unless the owner turned it off on the Developer screen; a key cannot change it. Off, a reply still uses the owner’s name, rules and writing style. Either way, nothing one customer wrote or was sent goes into another customer’s reply, and nothing from a sandbox conversation goes into a live one; every reply the account sends still shapes its writing style.
- updated_atstring (date-time) | null · required
- When the profile last changed. Null if it never has.
{
"business_name": "Example Co",
"description": "We make and sell refillable kitchen goods online, shipping to the US and Canada. We do not take phone orders.",
"tone_notes": "Warm and brief. Sign off as “The Example Co team”.",
"use_personal_context": true,
"updated_at": "2026-10-09T15:18:52.000Z"
}
Errors
- bad_request400
- The body is malformed — a field this route does not take, or one longer than it may be — or it tries to change use_personal_context, which only the account owner can, on the Developer screen.
- unauthorized401
- The key is missing, malformed, revoked, or not one we issued.
- missing_scope403
- The key does not carry brain:write.
- sandbox_read_only403
- A sandbox key can read knowledge but not change it.
- too_large413
- The request body is larger than this endpoint accepts.
- rate_limited429
- Over this route’s per-minute limit, counted per account and per key. Wait a minute.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.
POST/v1/developer/knowledge/uploads/{token}
Upload a file to a one-time address
Where the account’s own screen uploads a file directly (multipart `file`), with a one-time token from developerKnowledgeUploadUrl in place of a key.
Free30 requests a minute
For the Developer screen’s own uploads: the address carries a one-time token in place of a key. From your server, use POST /v1/developer/knowledge/sources.
curl -X POST "https://api.slyos.world/v1/developer/knowledge/uploads/$TOKEN" \
-H "Authorization: Bearer $SLYOS_KEY" \
-F 'file=@returns-policy.pdf' \
-F 'title=Returns policy'
Parameters
- tokenstring · in path · required
- The one-time token in the upload address SlyOS gave the Developer screen.20–200 characters
Request body — multipart/form-data
- filestring (binary) · required
- The file — PDF, Word (.docx), plain text, Markdown or CSV, up to the size this operation states. It is read to the end; a long one is cut into passages, not cut short.
- titlestring
- What to call it on the Developer screen and in a reply’s
sources.
202 response
Taken in, and read in the background.
- idstring (uuid) · required
- The source’s id.
- kindstring · required
link: one page. site: a whole site, read from one address. file: an upload.one of: link, site, file- urlstring | null · required
- The address it is read from. Null for a file.
- filenamestring | null · required
- The uploaded file’s name. Null for a link or a site.
- titlestring | null · required
- What it is called on the Developer screen and in a reply’s
sources. - rulesboolean · required
- True when replies must follow it; false when it is reference material.
- scopestring · required
project: replies asked for with this key’s project use it. account: replies in every project on the account do.one of: project, account- statusstring · required
queued, then processing, while it is read in the background; ready once replies use it; failed when it could not be read, with status_reason saying why.one of: queued, processing, ready, failed- status_reasonstring | null · required
- In a sentence, why the status is what it is. Null when there is nothing to say.
- warningstring | null · required
- Set when the source is
ready but some of what it shows may be missing, in a sentence naming the pages and what to do — today, pages that build their content with JavaScript, which SlyOS does not run (a price list drawn from a script, a template filled in after the page loads). Null when there is nothing to warn about. - incomplete_pagesarray of string · required
- The addresses of the pages
warning names: pages whose content is built with JavaScript, so replies may be missing what a visitor sees there. Add that text as a file, or as a single link to a page that shows it. Empty when there are none. - pagesinteger · required
- Pages read from it.
- passagesinteger · required
- Passages it was cut into: what a reply retrieves from.
- charactersinteger · required
- Characters of text read from it.
- size_bytesinteger | null · required
- The uploaded file’s size. Null for a link or a site.
- content_sha256string | null · required
- SHA-256 of the text read from it; it changes when a refresh reads something new.
- file_sha256string | null · required
- SHA-256 of the uploaded file’s bytes. Null for a link or a site.
- used_in_repliesinteger · required
- How many replies have relied on a passage of it.
- rules_fitboolean | null · required
- For a rules source: true when every one of the business’s rules reaches every reply; false when they no longer fit in one reply, and each reply gets the rules nearest its message. Null for reference material, or when it was not measured.
- rules_notestring | null · required
- When
rules_fit is false, in a sentence: how much the rules come to, what one reply carries, and what to do about it. - created_atstring (date-time) · required
- When it was added.
- updated_atstring (date-time) · required
- When it last changed.
- fetched_atstring (date-time) | null · required
- When it was last read. Null until it has been.
- duplicateboolean · required
- True when this address or this exact file was already a source: nothing new was added, and this is that source.
{
"id": "0e7c2a9d-5f1b-4d38-a6e4-9b3c1f7d2a85",
"kind": "file",
"url": null,
"filename": "returns-policy.pdf",
"title": "Returns policy",
"rules": true,
"scope": "project",
"status": "queued",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 0,
"passages": 0,
"characters": 0,
"size_bytes": 284311,
"content_sha256": null,
"file_sha256": "9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c",
"used_in_replies": 0,
"rules_fit": true,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:20:04.000Z",
"fetched_at": null,
"duplicate": false
}
200 response
That exact file is already a source: this is it. The same fields as the 202 response.
{
"id": "0e7c2a9d-5f1b-4d38-a6e4-9b3c1f7d2a85",
"kind": "file",
"url": null,
"filename": "returns-policy.pdf",
"title": "Returns policy",
"rules": true,
"scope": "project",
"status": "ready",
"status_reason": null,
"warning": null,
"incomplete_pages": [],
"pages": 0,
"passages": 0,
"characters": 0,
"size_bytes": 284311,
"content_sha256": null,
"file_sha256": "9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c",
"used_in_replies": 0,
"rules_fit": true,
"rules_note": null,
"created_at": "2026-10-09T15:20:04.000Z",
"updated_at": "2026-10-09T15:20:04.000Z",
"fetched_at": null,
"duplicate": true
}
Errors
- bad_request400
- No file in the upload, or the upload address is malformed.
- not_found404
- The upload address is unknown, used, or expired. Ask for a new one.
- too_many_sources409
- The account already holds the most knowledge sources it may.
- knowledge_full409
- The account already holds the most knowledge text it may.
- too_large413
- The request body is larger than this endpoint accepts.
- unsupported_type422
- Not a file type SlyOS reads (PDF, Word .docx, plain text, Markdown, CSV).
- rate_limited429
- Over this route’s per-minute limit, counted per account. Wait a minute.
- busy429
- Too many sources are being read at once. Add more when they finish.
- uploads_busy429
- Two files are already uploading for this account. Send the next after.
- internal500
- An unexpected fault on SlyOS’s side. It is recorded.