GenuineAIGenuineAI
For usersFor developers
  • Overview
  • Guides
  • How-to
  • API reference
Documentation
  • Quickstart
  • Authentication
  • Errors
  • Rate limits
  • API reference
Platform
  • Platform overview
  • Solutions
  • Pricing
  • Sign in
Company
  • Status
  • Trust Center
  • Contact
  • Terms of Service
  • Privacy Policy

© 2026 GenuineAI Ventures LLC

support@genuinehq.com
Media library
Uploading filesOrganizing and finding assetsDelivering assetsPublishing assets
AI
AI enrichmentPeople and facesAgents and conversations
Knowledge
Knowledge basesHow agents use knowledge
Automation
Autonomous AIExternal dataExtensions
Creating and deploying
Generating contentDeployed AI
Operations
Usage and credits
How-to

Agents and conversations

An agent is a configured model: a prompt, a model, a set of tools, and the knowledge it answers from. A thread is a conversation with an agent, and messages run the model.

Code
agent → thread → message → the reply streams back

Create an agent

agent_name, agent_description, agent_model, agent_temperature and agent_top_p are all required. agent_model is restricted: a workspace may use the platform's own genai- models, and foundation models only where they have been enabled for it. GET /agents on an existing agent is the quickest way to see what your workspace accepts.

agent_audience is internal or public, and agent_tools names the capabilities the agent may call. GET /agents/{id}/preview-system-prompt shows the composed system prompt, everything the agent's configuration, knowledge and tools add up to, without running anything. It is the fastest way to diagnose an agent that answers oddly.

GET /agents/{id}/history lists edits over time, so a change in behavior can be traced to a change in configuration.

Tools

agent_tools is what turns an agent from something that answers into something that acts. Each entry names a capability the model may call mid-conversation, on its own initiative:

Code
{ "agent_tools": ["photo_selector", "image_generation", "logo_selector"] }
ToolDoes
image_generationCreates a new image. Not bound when the agent's own model is already an image model.
create_designCreates an editable, layered design in the design library. Unlike an image, its headlines stay real text layers.
photo_selectorSearches the existing media library and picks photos. Selects; never creates.
logo_selectorChooses the brand logo that suits the content and the background it sits on.
brand_styleReads the workspace's brand colors and typography, so what the agent produces is styled in the brand.
kb_lookupLooks up records and reference images in the agent's knowledge bases on demand.
external_dataCalls a connected third-party service. See external data.
web_searchSearches the web.
url_contextReads the content at a URL.
mapsLooks up places and directions.

The distinction between image_generation and photo_selector is the one to get right, because users notice it: "make me a picture of a harbor" and "find me a picture of a harbor" are different requests, and an agent carrying only one of the two tools will confidently do the wrong thing. Give it both if it should be able to do either.

Unknown tool keys are ignored rather than refused, so a typo fails silently. Check GET /agents/{id} to confirm what was stored.

Tool calls in a thread

Tool calls appear in the thread as part of the exchange, and results that reference files (a selected photo, a generated image) carry the file_id, so you can render or download them like any other library file. GET /agents/{id}/preview-system-prompt shows the instructions each tool adds to the agent's prompt, which is the fastest way to understand why an agent reaches for one tool over another.

Knowledge bases

A knowledge base is a set of records an agent retrieves from. Names are unique in the workspace, because names are how agents refer to them:

TerminalCode
curl -X POST https://api.genuineai.app/api/v1/knowledge-bases \ -H "X-Api-Key: gai_…" -H "X-Tenant-Id: <workspace-id>" \ -H "Content-Type: application/json" \ -d '{"ds_name": "Brand guidelines", "ds_description": "Voice, tone and usage rules"}'

Building and filling one is a subject of its own. Knowledge bases covers the three types, schemas, importing and crawling, and how agents use knowledge covers how an agent uses what you put there.

Attach knowledge to an agent:

TerminalCode
curl -X PATCH https://api.genuineai.app/api/v1/agents/<agent-id>/ds \ -H "X-Api-Key: gai_…" -H "X-Tenant-Id: <workspace-id>" \ -H "Content-Type: application/json" \ -d '{"agent_tenant_ds": ["3f2a9c1e-…", "8a1b6e5c-…"]}'

Two fields, deliberately separate. agent_ds is the agent's own default set, named in kebab-case. agent_tenant_ds is your workspace's selection layered on top. Send null to drop the override and fall back to the agent's default.

Knowledge bases do more than answer questions. The Media Tags and Flags knowledge bases are the controlled vocabulary image analysis is allowed to use. Editing them changes how every future upload is described.

Threads

You supply the thread id. thread_id is required in the body rather than generated for you, so mint a UUID client-side. That makes thread creation idempotent from your side: a retry after a timeout reuses the id rather than leaving two conversations behind.

thread_share_mode decides who else can see the thread: private, space (everyone in the space) or collab. thread_space puts it in a space, which requires write access to that space.

For a conversation attached to something else, such as a file or a task, POST /threads/actions/find-or-create takes a thread_ref and returns the existing thread or starts one. It is a POST because it writes. To read without creating, use GET /threads?thread_ref=….

A thread's files

Code
GET /threads/{id}/files

Everything belonging to the conversation: what was attached to it, and what was generated in it. Reading these files means reading the conversation, so its access rules apply on top of each file's.

An image generated inside a conversation belongs to two places at once: that thread, and the generated library where every AI output lands. It is returned by this listing and by GET /media-files?repo_type=generated alike. See organizing assets for the repository vocabulary.

Send a message

Code
POST /threads/{id}/messages

msg_content is an array of parts rather than a string, which is how a message carries files from your library alongside its text:

Code
{ "msg_content": [ { "type": "text", "text": "Which of these would work as a homepage hero?" }, { "type": "image_url", "file_id": "8a1b6e5c-…", "file_name": "harbor-sunset.jpg", "file_type": "image/jpeg" } ] }
Part type
textCarries text.
image_urlAn image from the library, by file_id.
fileA document from the library, by file_id.
referenceA file to retrieve against rather than attach whole.

This is the endpoint that runs a model. It consumes credits and counts against the expensive rate-limit tier.

The reply streams on the response

The response body is the assistant's reply, written as it is generated. Read it as a stream of text rather than waiting for a complete JSON document:

The response carries Content-Type: text/event-stream, but the body is plain text chunks, not SSE frames. There are no event: or data: lines to parse. Append them as they arrive. The structured events are on the separate stream below.

The finished message is persisted either way, so a dropped connection loses the live output but not the reply, which remains available from GET /threads/{id}/messages.

Retry a message

retry: true re-runs the last exchange. It removes the previous assistant message only if that message failed, so a retry after an error does not duplicate a good answer.

For image generation, imageQuality (1K, 2K, 4K) and aspectRatio are accepted and remembered on the thread.

The event stream

Code
GET /threads/{id}/events

A properly framed SSE stream, for following a conversation that more than one client is watching:

Event
helloSent on connect: the thread's current status, who it is generating for, and who is present.
user_messageSomeone posted a message.
assistant_messageA reply completed.
lockThe thread started or stopped generating, and for whom.
presenceWho is viewing or typing.

A : keepalive comment arrives every 25 seconds. Ignore it, and do not treat the absence of events as a dead connection any sooner than that.

Events are broadcast only for shared threads. A private, single-user thread publishes nothing but hello and presence; its reply arrives on the POST response described above. Do not wait on the event stream for a conversation only your integration is having, because the events never arrive.

POST /threads/{id}/presence reports that you are viewing or typing, which is what populates other clients' presence events.

The generating lock

A shared thread accepts one generation at a time. Posting while it is busy returns 409, because the reply to someone else's message is still being written. Wait for the lock event reporting thread_status: "idle" rather than retrying immediately.

Private threads do not take the lock, so they never return 409 for this reason.

Reusable prompts

A prompt is a saved instruction with declared inputs, so the same task is not retyped differently every time. GET /prompts/{id}/form returns the inputs it asks for, and wildcards (/wildcards) define how each is collected: a free-text box, a list, or a file picker.

Send one by including a form part in msg_content naming the prompt_id. The platform resolves it into text and attachments before the model sees it.

Prompts are organized with categories rather than free-text tags. GET /prompt-categories returns the workspace's own terms plus the product-shipped ones, and PUT /prompts/{id}/categories files a prompt. Filing is per workspace, so filing a product prompt affects nobody else. Filter the catalog with the prompt_tenant_categories parameter on GET /prompts.

Memories

/memories holds what an agent remembers about the calling user between conversations. GET lists them, POST adds one, and DELETE /memories clears them all. Memories are per user rather than per workspace, so one person's memories never inform another's conversations.

Next steps

  • AI enrichment covers the analysis that makes library files answerable.
  • Organizing and finding assets is how you find the files to attach.
  • Rate limits describes the expensive tier that governs every model call.
Last modified on October 8, 2026
People and facesKnowledge bases
On this page
  • Create an agent
  • Tools
    • Tool calls in a thread
  • Knowledge bases
  • Threads
    • A thread's files
  • Send a message
    • The reply streams on the response
    • Retry a message
  • The event stream
    • The generating lock
  • Reusable prompts
  • Memories
  • Next steps
curl -X POST https://api.genuineai.app/api/v1/agents \ -H "X-Api-Key: gai_…" -H "X-Tenant-Id: <workspace-id>" \ -H "Content-Type: application/json" \ -d '{ "agent_name": "Archive researcher", "agent_description": "Answers questions about the photo archive", "agent_model": "genai-standard", "agent_temperature": "0.3", "agent_top_p": "0.95", "agent_audience": "internal" }'
JSON
curl -X POST https://api.genuineai.app/api/v1/threads \ -H "X-Api-Key: gai_…" -H "X-Tenant-Id: <workspace-id>" \ -H "Content-Type: application/json" \ -d '{ "thread_id": "d9f1c2b4-6a55-4f0e-9c3a-1b2d3e4f5a6b", "thread_agent": "3f2a9c1e-…", "thread_title": "Q3 archive questions" }'
JSON
const res = await fetch( `https://api.genuineai.app/api/v1/threads/${threadId}/messages`, { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ msg_content: [{ type: "text", text: "Summarize this album." }], }), }, ); const reader = res.body.getReader(); const decoder = new TextDecoder(); let reply = ""; for (;;) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value, { stream: true }); reply += chunk; process.stdout.write(chunk); }