Agents Completions API
Creates a model response for a given Agent using Vercel AI SDK compatible format.
Creates a model response for a given agent ID, or pass in an Agent configuration that should be used for your request. This endpoint uses the Vercel AI SDK compatible message format for seamless integration with modern AI applications.
Before You Start
- Agent access: To share an agent with an API key, follow this guide.
- Vercel AI SDK compatible: This endpoint uses the Vercel AI SDK's UIMessage format, making it compatible with the
useChathook and other Vercel AI SDK features. - MCP: You can also access your agents via the ajan MCP Server, which lets MCP-compatible AI clients call your agents directly.
Base URL
https://api.ajan.io/agent/v1/chat/completionsParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agentId | string | One of agentId/agent required | ID of an existing agent to use |
agent | object | One of agentId/agent required | Configuration for a temporary agent |
messages | array | Yes | Array of UIMessage objects (Vercel AI SDK format) |
stream | boolean | No | Enable streaming responses (default: false) |
output | object | No | Structured output format specification |
maxSteps | integer | No | Maximum number of tool steps (1-20) |
imageResponseFormat | string | No | Response format for agent-generated images. "url" returns a signed URL, "b64_json" returns base64-encoded image data. |
Message Format (Vercel AI SDK UIMessage)
The Agents API uses the Vercel AI SDK's UIMessage format for maximum compatibility with modern AI frameworks.
UIMessage Structure
Each message in the messages array should contain:
interface UIMessage {
id: string; // Unique identifier for this message
role: 'system' | 'user' | 'assistant';
parts: MessagePart[]; // Array of message parts
metadata?: { // Optional metadata
attachments?: string[]; // Array of attachment UUIDs
};
}Message Part Types
User message parts (for sending):
| Type | Fields | Description |
|---|---|---|
text | type: "text", text: string | Plain text content |
file | type: "file", mediaType: string, url: string, filename?: string | Inline file reference |
Agent message parts (returned in responses — include in conversation history when sending follow-up messages):
| Type | Key Fields | Description |
|---|---|---|
text | type: "text", text: string | Text response |
reasoning | type: "reasoning", text: string | Model reasoning / chain-of-thought |
tool-{name} | type: "tool-{name}", toolCallId: string, state: "input-streaming" | "input-available" | "output-available" | "output-error", input?: any, output?: any, errorText?: string | Tool call and result |
source-url | type: "source-url", sourceId: string, url: string, title?: string | Web source reference |
source-document | type: "source-document", sourceId: string, mediaType: string, title: string, filename?: string | Document source reference |
Example Messages
User Message with Text
{
id: "msg_1",
role: "user",
parts: [
{
type: "text",
text: "Hello, how are you?"
}
]
}User Message with Attachment
{
id: "msg_2",
role: "user",
parts: [
{
type: "text",
text: "Please analyze this document"
}
],
metadata: {
attachments: ["550e8400-e29b-41d4-a716-446655440000"]
}
}Agent Message with Tool Call
{
id: "msg_3",
role: "assistant",
parts: [
{
type: "tool-webSearch",
toolCallId: "call_123",
state: "output-available",
input: {
query: "latest news"
},
output: { /* search results */ }
}
]
}Agent Configuration
When creating a temporary agent using the agent parameter, you can specify:
name- Name of the agent (max 64 chars)instructions- System instructions (max 16384 chars)description- Optional description (max 256 chars)temperature- Temperature between 0-1model- Model ID to use (see Available Models for options)capabilities- Enable features like web search, Create & work with files, image generation, canvasknowledgeFolderIds- IDs of Knowledge bases to useattachmentIds- Array of UUID strings identifying attachments to use
Configuration Notes
- Available models: Retrieve a list of available models using the Models API.
- Field naming: The inline agent configuration field names differ from the Create and Update Agent APIs. This endpoint uses
instructions(plural) andtemperature, while the CRUD endpoints useinstruction(singular) andcreativity. The completions endpoint also accepts a nestedcapabilitiesobject, while the CRUD endpoints use flat boolean fields. attachmentIdscurrently not functional: The agent cannot read files referenced throughattachmentIdsin the inline agent configuration. Instead, usemetadata.attachmentson individual messages to reference uploaded files per message, or create a persistent agent with theattachmentsfield via the Create Agent API.
Using Tools via API
When an agent has tools configured (called "Actions" in the ajan UI), it will automatically use them to respond to API requests when appropriate.
Tools authenticate with a preselected connection on the agent, or with a connection shared with the API key.
Structured Output
You can specify a structured output format using the optional output parameter:
| Field | Type | Description |
|---|---|---|
type | "object" | "array" | "enum" | The type of structured output |
schema | object | JSON Schema definition for the output (for object/array types) |
enum | string\[] | Array of allowed values (for enum type) |
The output parameter behavior depends on the specified type:
type: "object"with no schema: Forces the response to be a single JSON object (no specific structure)type: "object"with schema: Forces the response to match the provided JSON Schematype: "array"with schema: Forces the response to be an array of objects matching the provided schematype: "enum": Forces the response to be one of the values specified in theenumarray
Streaming Responses
When stream is set to true, the API returns a stream using the Vercel AI SDK streaming format, compatible with the useChat hook and other Vercel AI SDK features.
Using with Vercel AI SDK useChat Hook
'use client';
import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: 'https://api.ajan.io/agent/v1/chat/completions',
headers: {
'Authorization': `Bearer ${process.env.NEXT_PUBLIC_AJAN_API_KEY}`
},
body: {
agentId: 'your-agent-id'
}
});
return (
<div>
{messages.map(m => (
<div key={m.id}>
{m.role === 'user' ? 'User: ' : 'AI: '}
{m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
placeholder="Say something..."
onChange={handleInputChange}
/>
</form>
</div>
);
}Manual Stream Handling
const response = await fetch('https://api.ajan.io/agent/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
agentId: 'agent_123',
messages: [
{
id: 'msg_1',
role: 'user',
parts: [{ type: 'text', text: 'Hello' }]
}
],
stream: true
}),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
console.log(chunk); // Process streaming chunks
}Obtaining Attachment IDs
To use attachments in your agent conversations, first upload the files using the Upload Attachment API. This returns an attachmentId (UUID) for each file. You can then use attachments in two ways:
- Per-message (recommended): Include the attachment UUIDs in the message's
metadata.attachmentsarray. This lets you reference different files in different messages within the same conversation. - Agent-level: Include the UUIDs in the
attachmentsarray when creating or updating a persistent agent. All messages sent to that agent will have access to these files.
Response Format
The API returns a JSON object containing a messages array with the agent's response:
interface CompletionResponse {
messages: Array<{
id: string;
role: "assistant";
content: string;
}>;
// Structured output - included when requested
output?: object | array | string;
}Standard Response
The response contains a messages array. Each message has:
id- Unique identifier for the messagerole- Always"assistant"for completion responsescontent- The agent's text response as a plain string
Structured Output
When the request includes an output parameter, the response will automatically include an output field containing the formatted structured data. The type of this field depends on the requested output format:
- If
output.typewas "object": Returns a JSON object (with schema validation if schema was provided) - If
output.typewas "array": Returns an array of objects matching the provided schema - If
output.typewas "enum": Returns a string matching one of the provided enum values
Examples
Using an Existing Agent with Attachment
const response = await fetch(
"https://api.ajan.io/agent/v1/chat/completions",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
agentId: "agent_123",
messages: [
{
id: "msg_1",
role: "user",
parts: [
{
type: "text",
text: "Can you analyze this document for me?"
}
],
metadata: {
attachments: ["550e8400-e29b-41d4-a716-446655440000"]
}
}
]
})
}
);
const data = await response.json();
const responseText = data.messages[0].content;
console.log(responseText);Using a Temporary Agent Configuration
const response = await fetch(
"https://api.ajan.io/agent/v1/chat/completions",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
agent: {
name: "Document Analyzer",
instructions: "You are a helpful agent who analyzes documents and answers questions about them",
temperature: 0.7,
model: "gpt-5",
capabilities: {
webSearch: true
}
},
messages: [
{
id: "msg_1",
role: "user",
parts: [
{
type: "text",
text: "What are the key points in the document?"
}
]
}
]
})
}
);
const data = await response.json();
console.log(data);Using Structured Output with Schema
const response = await fetch(
"https://api.ajan.io/agent/v1/chat/completions",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
agent: {
name: "Weather Agent",
instructions: "You are a helpful weather agent",
model: "gpt-5",
capabilities: {
webSearch: true
}
},
messages: [
{
id: "msg_1",
role: "user",
parts: [
{
type: "text",
text: "What's the weather in Paris, Berlin and London today?"
}
]
}
],
output: {
type: "array",
schema: {
type: "object",
properties: {
weather: {
type: "object",
properties: {
city: { type: "string" },
tempInCelsius: { type: "number" },
tempInFahrenheit: { type: "number" }
},
required: ["city", "tempInCelsius", "tempInFahrenheit"]
}
}
}
}
})
}
);
const data = await response.json();
console.log(data.output);
// Output:
// [
// { "weather": { "city": "Paris", "tempInCelsius": 1, "tempInFahrenheit": 33 } },
// { "weather": { "city": "Berlin", "tempInCelsius": 1, "tempInFahrenheit": 35 } },
// { "weather": { "city": "London", "tempInCelsius": 7, "tempInFahrenheit": 45 } }
// ]Using with Next.js Server Actions
// app/actions.ts
'use server';
import { generateId } from 'ai';
export async function chatWithAgent(message: string) {
const response = await fetch(
'https://api.ajan.io/agent/v1/chat/completions',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.AJAN_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
agentId: process.env.AGENT_ID,
messages: [
{
id: generateId(),
role: 'user',
parts: [
{
type: 'text',
text: message
}
]
}
]
})
}
);
const data = await response.json();
return data.messages[0].content;
}Rate Limits
The default limits are 500 RPM (requests per minute) and 150,000 TPM (tokens per minute).
- RPM is enforced per workspace, model, and API key.
- TPM is shared by all API keys using the same model in a workspace.
- On dedicated deployments, admins can configure custom limits per model in Settings > Workspace > Products > API.
If you exceed your rate limit, you will receive a 429 Too Many Requests response.
Error Handling
try {
const response = await fetch('https://api.ajan.io/agent/v1/chat/completions', options);
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Request failed');
}
const data = await response.json();
// Process response
} catch (error) {
console.error('Error:', error.message);
}Common error status codes:
400- Invalid request parameters, malformed message format, agent not found, or agent not shared with API key401- Invalid or missing API key429- Rate limit exceeded500- Server error
OpenAPI
openapi: 3.0.0
info:
title: ajan API
version: 3.0.0
servers:
- url: https://api.ajan.io
description: Production
security:
- bearerAuth: []
paths:
/agent/v1/chat/completions:
post:
tags:
- Agent
summary: Creates a chat completion with an agent (Vercel AI SDK compatible)
description: Creates a model response using Vercel AI SDK compatible UIMessage format
parameters: []
requestBody:
required: true
content:
application/json:
examples:
streamingEnabled:
summary: Request with streaming enabled
value:
agentId: agent_123
messages:
- id: msg_1
role: user
parts:
- type: text
text: Hello, how can you help me?
stream: true
schema:
type: object
oneOf:
- type: object
required:
- agentId
- messages
properties:
agentId:
type: string
description: ID of an existing agent to use
messages:
type: array
description: Array of UIMessage objects (Vercel AI SDK format)
items:
type: object
required:
- id
- role
- parts
properties:
id:
type: string
description: Unique message identifier
role:
type: string
enum:
- user
- assistant
- system
- tool
parts:
type: array
items:
type: object
required:
- type
properties:
type:
type: string
enum:
- text
- file
- tool-invocation
- tool-result
text:
type: string
description: Text content for text parts
url:
type: string
description: File URL for file parts
name:
type: string
description: File name
mimeType:
type: string
description: MIME type of the file
toolCallId:
type: string
description: Tool call identifier
toolName:
type: string
description: Name of the tool
args:
type: object
description: Tool arguments
result:
type: object
description: Tool result
stream:
type: boolean
default: false
output:
$ref: '#/components/schemas/StructuredOutputConfig'
imageResponseFormat:
type: string
enum:
- url
- b64_json
description: >-
Response format for images generated by the agent. "url"
returns a signed URL, "b64_json" returns base64-encoded
image data.
responses:
'200':
description: Successful chat completion
content:
application/json:
schema:
type: object
description: UIMessage response (Vercel AI SDK format)
required:
- id
- role
- parts
properties:
id:
type: string
role:
type: string
enum:
- assistant
parts:
type: array
items:
type: object
output:
description: Structured output if requested
'400':
description: Invalid request parameters
'429':
description: Rate limit exceeded
'500':
description: Internal server error
components:
schemas:
StructuredOutputConfig:
type: object
description: >-
Specification for structured output format. When type is object/array
and no schema is provided, the response will be JSON but can have any
structure. When the type is enum, you must provide an enum parameter
with an array of strings as options.
properties:
type:
type: string
enum:
- object
- array
- enum
description: The type of structured output
schema:
type: object
description: >-
JSON Schema definition for the output (required for object/array
types with specific structure). Search for "JSON to JSON Schema" in
the web to find a tool to convert any JSON into the required JSON
Schema format.
enum:
type: array
items:
type: string
description: >-
Array of allowed values (required for enum type). Values must be of
type string.
oneOf:
- properties:
type:
enum:
- enum
enum:
items:
type: string
type: array
- properties:
type:
enum:
- object
- array
schema:
type: object
- properties:
type:
enum:
- object
- array
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: API Key
description: API key as Bearer token. Format "Bearer YOUR_API_KEY"