API Users
Pull your team's Contexts into any product surface.
Use Oi as the prompt source of truth for assistants, internal tools, jobs, and workflow automation.
Why developers care
No prompt strings in code
Fetch one shared Context instead of hardcoding prompts into product routes, workers, and tools.
One source of truth
Use the same context across assistants, internal tools, jobs, and product workflows.
Update without deploys
Change the Context in Oi and let clients pick up the latest version.
Public to private path
Start from public contexts, then use private org-specific versions through the same API shape.
Documentation
Contexts
Context API
Get Context
Fetch one Context directly. Use the Context slug, for example `designer`.
# current version
curl -sS \
-H "Authorization: Bearer $OI_API_KEY" \
"https://api.oioioi.ai/v1/contexts/:slug"
# specific historical version
curl -sS \
-H "Authorization: Bearer $OI_API_KEY" \
"https://api.oioioi.ai/v1/contexts/:slug?version=2"from urllib.request import Request, urlopen
request = Request(
"https://api.oioioi.ai/v1/contexts/:slug",
headers={"Authorization": "Bearer " + OI_API_KEY},
)
with urlopen(request) as response:
print(response.read().decode("utf-8"))const response = await fetch("https://api.oioioi.ai/v1/contexts/:slug", {
headers: {
Authorization: `Bearer ${process.env.OI_API_KEY}`,
},
});
const payload = await response.json();
console.log(payload.content);// Current version.
const response = await fetch(
"https://api.oioioi.ai/v1/contexts/:slug",
{
headers: {
Authorization: `Bearer ${process.env.OI_API_KEY ?? ""}`,
},
},
);
// Specific historical version.
const versionedResponse = await fetch(
"https://api.oioioi.ai/v1/contexts/:slug?version=2",
{
headers: {
Authorization: `Bearer ${process.env.OI_API_KEY ?? ""}`,
},
},
);
const payload = (await response.json()) as GetContextResponse;
const versionedPayload = (await versionedResponse.json()) as GetContextResponse;
console.log(payload.content);
console.log(versionedPayload.content);var request = java.net.http.HttpRequest.newBuilder()
.uri(java.net.URI.create("https://api.oioioi.ai/v1/contexts/:slug"))
.header("Authorization", "Bearer " + System.getenv("OI_API_KEY"))
.build();
var client = java.net.http.HttpClient.newHttpClient();
var response = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());req, err := http.NewRequest(
http.MethodGet,
"https://api.oioioi.ai/v1/contexts/:slug",
nil,
)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("OI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))require "net/http"
require "uri"
uri = URI("https://api.oioioi.ai/v1/contexts/:slug")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("OI_API_KEY")}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts response.bodyList Contexts
Use limit and cursor for simple pagination. Start here when you want to see what your team has available.
# default fields include markdown content
curl -sS \
-H "Authorization: Bearer $OI_API_KEY" \
"https://api.oioioi.ai/v1/contexts?limit=10"from urllib.request import Request, urlopen
request = Request(
"https://api.oioioi.ai/v1/contexts?limit=10",
headers={"Authorization": "Bearer " + OI_API_KEY},
)
with urlopen(request) as response:
print(response.read().decode("utf-8"))const response = await fetch("https://api.oioioi.ai/v1/contexts?limit=10", {
headers: {
Authorization: `Bearer ${process.env.OI_API_KEY}`,
},
});
const payload = await response.json();
console.log(payload.items[0]?.content);// Default fields include markdown content.
const defaultResponse = await fetch("https://api.oioioi.ai/v1/contexts?limit=10", {
headers: {
Authorization: `Bearer ${process.env.OI_API_KEY ?? ""}`,
},
});
const defaultPayload = (await defaultResponse.json()) as ListContextsResponse;
console.log(defaultPayload.items[0]?.content);var request = java.net.http.HttpRequest.newBuilder()
.uri(java.net.URI.create("https://api.oioioi.ai/v1/contexts?limit=10"))
.header("Authorization", "Bearer " + System.getenv("OI_API_KEY"))
.build();
var client = java.net.http.HttpClient.newHttpClient();
var response = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());req, err := http.NewRequest(
http.MethodGet,
"https://api.oioioi.ai/v1/contexts?limit=10",
nil,
)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("OI_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))require "net/http"
require "uri"
uri = URI("https://api.oioioi.ai/v1/contexts?limit=10")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("OI_API_KEY")}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts response.bodyContext Request and Response Types
Use these language definitions as the query parameter and response shape reference. These GET endpoints do not accept JSON request bodies.
Did you know?
- `content` is the compiled markdown Context payload for display, inspection, and durable client behavior.
type ContextResponse = {
name: string;
shortDescription: string;
content?: string;
usage?: {
usageEventId: string;
source: "api";
operation: "get_context";
promptTokenEstimate?: number;
};
};
type ListContextsResponse = {
items: ContextResponse[];
pagination: {
page: number;
pageSize: number;
totalCount: number;
totalPages: number;
nextCursor?: string;
hasNextPage: boolean;
};
};
type ListContextsQueryParams = {
cursor?: string;
limit?: number;
};
type GetContextPathParams = {
slug: string;
};
type GetContextQueryParams = {
version?: number;
};
type GetContextResponse = ContextResponse;from typing import Literal, NotRequired, TypedDict
class ContextUsage(TypedDict, total=False):
usageEventId: str
source: Literal["api"]
operation: Literal["get_context"]
promptTokenEstimate: int
class ContextResponse(TypedDict, total=False):
name: str
shortDescription: str
content: str
usage: NotRequired[ContextUsage]
class ListContextsResponse(TypedDict, total=False):
items: list[ContextResponse]
pagination: dict[str, int | str | bool]
class ListContextsQueryParams(TypedDict, total=False):
cursor: str
limit: int
class GetContextPathParams(TypedDict):
slug: str
class GetContextQueryParams(TypedDict, total=False):
version: int
class GetContextResponse(ContextResponse):
pass/**
* @typedef {Object} ContextResponse
* @property {string} name
* @property {string} shortDescription
* @property {string=} content
* @property {{ usageEventId: string, source: "api", operation: "get_context", promptTokenEstimate?: number }=} usage
*/Context Example Responses
Use these JSON payloads as concrete examples of Context API responses.
Get Context
{
"name": "Designer",
"shortDescription": "Reviews flows, UX details, and design direction.",
"content": "# Designer\n\nReviews flows, UX details, and design direction.\n\n## Instructions\n\nAct as the organization's design collaborator.",
"usage": {
"usageEventId": "usage_123",
"source": "api",
"operation": "get_context",
"promptTokenEstimate": 620
}
}List Contexts
{
"items": [
{
"name": "Designer",
"shortDescription": "Reviews flows, UX details, and design direction.",
"content": "# Designer\n\nReviews flows, UX details, and design direction.\n\n## Instructions\n\nAct as the organization's design collaborator."
}
],
"pagination": {
"page": 1,
"pageSize": 10,
"totalCount": 24,
"totalPages": 3,
"nextCursor": "context#designer",
"hasNextPage": true
}
}Workflows
Workflow API
List Workflows
List organization Workflows for the API key's organization. Use `q`, `limit`, `page`, or `cursor` to search and paginate.
curl -sS \
-H "Authorization: Bearer $OI_API_KEY" \
"https://api.oioioi.ai/v1/workflows?limit=10"const response = await fetch("https://api.oioioi.ai/v1/workflows?limit=10", {
headers: {
Authorization: `Bearer ${process.env.OI_API_KEY ?? ""}`,
},
});
const payload = (await response.json()) as ListWorkflowResponse;
console.log(payload.items[0]?.content);Get Workflow
Fetch one organization Workflow by `workflowId`. Use `?version=2` to request a historical version.
curl -sS \
-H "Authorization: Bearer $OI_API_KEY" \
"https://api.oioioi.ai/v1/workflows/:workflowId"const response = await fetch(
"https://api.oioioi.ai/v1/workflows/:workflowId",
{
headers: {
Authorization: `Bearer ${process.env.OI_API_KEY ?? ""}`,
},
},
);
const payload = (await response.json()) as WorkflowResponse;
console.log(payload.content);Workflow Response Type
Organization Workflow responses follow the same top-level shape as Contexts: `content` is the compiled markdown payload.
type WorkflowResponse = {
name: string;
shortDescription: string;
content?: string;
usage?: {
usageEventId: string;
source: "api";
operation: "get_workflow";
promptTokenEstimate?: number;
};
};
type PublicWorkflowDetailResponse = WorkflowResponse;
type ListWorkflowResponse = {
items: WorkflowResponse[];
pagination: {
page: number;
pageSize: number;
totalCount: number;
totalPages: number;
nextCursor?: string;
hasNextPage: boolean;
};
};from typing import TypedDict
class WorkflowResponse(TypedDict, total=False):
name: str
shortDescription: str
content: str
usage: dict[str, str | int]
class PublicWorkflowDetailResponse(WorkflowResponse):
pass
class ListWorkflowResponse(TypedDict):
items: list[WorkflowResponse]
pagination: dict[str, int | str | bool]/**
* @typedef {Object} WorkflowResponse
* @property {string} name
* @property {string} shortDescription
* @property {string=} content
* @property {{ usageEventId: string, source: "api", operation: "get_workflow", promptTokenEstimate?: number }=} usage
*
* @typedef {Object} PublicWorkflowDetailResponse
* @property {string} name
* @property {string} shortDescription
* @property {string=} content
* @property {{ usageEventId: string, source: "api", operation: "get_workflow", promptTokenEstimate?: number }=} usage
*
* @typedef {Object} ListWorkflowResponse
* @property {WorkflowResponse[]} items
* @property {{ page: number, pageSize: number, totalCount: number, totalPages: number, nextCursor?: string, hasNextPage: boolean }} pagination
*/Workflow Example Responses
Guardrails appear inside the compiled Workflow `content` and nested Contexts expose markdown `content` inside that compiled payload.
Get Workflow
{
"name": "Launch Review",
"shortDescription": "Run a launch-readiness review.",
"content": "# Launch Review\n\nRun a launch-readiness review...",
"usage": {
"usageEventId": "usage_456",
"source": "api",
"operation": "get_workflow"
}
}Get Workflows
{
"items": [
{
"name": "Launch Review",
"shortDescription": "Run a launch-readiness review.",
"content": "# Launch Review\n\nRun a launch-readiness review..."
}
],
"pagination": {
"page": 1,
"pageSize": 10,
"totalCount": 24,
"totalPages": 3,
"nextCursor": "workflow#launch-review",
"hasNextPage": true
}
}Errors
Error payloads use a small JSON shape that can be handled the same way across Context and Workflow endpoints.
{
"error": "entitlement_feature_unavailable(feature:api_access,plan:free,required:pro)",
"feature": "api_access",
"requiredPlan": "pro",
"upgradePath": "/dashboard/organization/billing"
}