API Usage and Tokens
This page is the practical guide to calling the Workspace from external code: how to authenticate, how to invoke endpoints, how to handle errors, pagination, retries, and versioning. For the conceptual map of API surfaces, see API Overview. For the exact contract of each built-in route, see the REST API reference.
Picking the right token
Three token types — pick the smallest blast radius that fits the caller:
| Caller | Token type | Where it comes from |
|---|---|---|
| A user signed into the UI or a custom interface | Session JWT | The login flow (POST /api/login/create, or SSO). |
| A connector running on your CI server or a job runner | API token, scoped to ingestion |
Settings → API Tokens in the workspace UI. |
| A third-party system that only calls one of your endpoints | Endpoint token, scoped to the endpoint path | Settings → Custom Endpoints → → Tokens. |
The complete scope matrix and rotation procedure is on Token scopes.
Creating an API token
- Sign in as an admin.
- Settings → API Tokens → Create token.
- Name the token after the caller (e.g.,
crm-sync-connector). - Pick the smallest set of scopes the caller needs (
ingestion,read,search,endpoints:run, …). - Copy the token — it's displayed once and can't be recovered.
- Store the token in your secret manager. Reference it from runtime config; never commit it to source.
Sending requests
All authenticated requests use a bearer header:
Authorization: Bearer <token>
Content-Type: application/json
Accept: application/json
Bodies are JSON. Avoid query-string tokens — they leak into proxy logs.
Calling a custom endpoint (curl)
curl -X POST "https://workspace.example.com/api/endpoints/run/similar-tickets" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "screen flicker after firmware update",
"productSku": "PRO-14",
"limit": 5
}'
Calling a custom endpoint with an endpoint token
curl -X POST "https://workspace.example.com/api/endpoints/token/run/similar-tickets" \
-H "Authorization: Bearer $ENDPOINT_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "query": "..." }'
Calling from C# (Curiosity.Library)
using var workspace = await Workspace.ConnectAsync(
baseUrl: "https://workspace.example.com",
apiToken: Environment.GetEnvironmentVariable("WORKSPACE_TOKEN"));
// Inside the workspace — your connector code uses the SDK directly.
await workspace.Graph.CreateNodeSchemaAsync<Ticket>();
workspace.Graph.TryAdd(new Ticket { Id = "T-1", Subject = "..." });
await workspace.Graph.CommitPendingAsync();
Calling from Python
import os, requests
token = os.environ["WORKSPACE_TOKEN"]
r = requests.post(
"https://workspace.example.com/api/endpoints/run/similar-tickets",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={"query": "screen flicker", "limit": 5},
timeout=30,
)
r.raise_for_status()
print(r.json())
Response shape
Successful responses are bare JSON values shaped by your endpoint:
[
{
"UID": "abc123…",
"Type": "Ticket",
"Id": "T-9182",
"Subject": "Screen flicker after 5.1.2 firmware"
}
]
Errors share a standard envelope (see Error codes):
{
"error": {
"code": "insufficient_scope",
"message": "Token is valid but missing the 'ingestion' scope.",
"details": { "required": "ingestion", "granted": ["read"] }
},
"traceId": "0HMVGB1J8K8I3:00000007"
}
Always log the traceId from error responses — it correlates 1:1 with server-side logs.
Pagination
List-style endpoints accept skip and take query parameters and return:
{ "items": [...], "total": 1248, "skip": 0, "take": 50 }
Treat total as advisory for large traversals. The robust pattern:
skip, take = 0, 100
while True:
page = requests.post(url, json={"skip": skip, "take": take}, ...).json()
for item in page["items"]:
process(item)
if len(page["items"]) < take:
break
skip += take
Rate limiting and retries
The workspace can return 429 Too Many Requests with a Retry-After: <seconds> header. The recommended client retry policy:
- Retry on
429,502,503,504, and other transient5xxresponses with noerror.codeset. - Use exponential backoff with jitter capped at 60 seconds.
- Stop after 5 attempts and surface the failure.
A C# helper is in Error codes → Retry policy template.
Do not retry:
400,401,403,404,409,422— these need a code change or a config change, not another attempt.
Versioning
- Built-in routes are versioned by the workspace image tag (
curiosityai/curiosity:vX.Y.Z). Breaking changes ship with a major version bump. - Your custom endpoints are versioned by you. The recommended convention is to put the version in the endpoint name (
similar-tickets-v2) and keep the previous version live during the deprecation window. - Endpoint and AI tool definitions can be exported from the workspace and stored in git, so promotions across environments are reviewable diffs.
What to put behind a custom endpoint vs an API call
| Need | Surface |
|---|---|
| Insert/update graph data on a schedule | API call via Curiosity.Library SDK from your connector |
| Run a domain-specific search that combines facets, graph constraints, and ranking | Custom endpoint |
| Expose graph queries to an external dashboard | Custom endpoint with an endpoint token |
| Let the chat assistant retrieve data | AI tool |
| Periodic enrichment / reindex / aggregate | Scheduled task |
Next steps
- REST API reference — exact request/response shapes.
- Custom Endpoints — write the server side that consumes these tokens.
- AI Tools — chat-accessible endpoints.
- Token scopes — the full scope matrix.
- Error codes — every code, what it means, and how to react.