API Capabilities¶
An API capability (type: "api") turns any HTTP(S) endpoint into a tool your agent can call. You describe the endpoint — its URL, method, and parameters — and PrimeThink builds a typed tool from it. When the model decides to use the tool, the platform makes the request and returns the response back to the model.
No code is required: an API capability is just a configuration blob. This is the simplest way to connect an agent to a third-party REST API or one of your own internal services.
For the bigger picture of how capabilities fit together, see Capabilities.
Options schema¶
The capability's behavior is defined entirely by its options:
{
"name": "get_weather",
"description": "Get current weather for a location",
"method": "GET",
"url": "https://api.weather.com/v1/current",
"params": {
"location": { "type": "string", "description": "City name", "required": true }
},
"headers": {
"Authorization": "Bearer ${WEATHER_API_KEY}"
},
"body": {
"query": { "type": "string", "description": "Search query", "required": true }
}
}
Field reference¶
| Key | Required | Default | Description |
|---|---|---|---|
url | Yes | — | Endpoint URL. Must be HTTPS. May contain ${SETTING} placeholders. Surrounding whitespace is stripped automatically. |
name | No* | falls back to the capability name, slugified | The function name the model sees. Must be valid (letters, digits, underscores). |
description | No | falls back to the capability description, then "Call the {tool_name} API" | Tells the model when to use the tool. |
method | No | GET | HTTP method. Allowed: GET, POST, PUT, PATCH. (DELETE and others are rejected.) Case-insensitive. |
params | No | — | Query-string parameters → field schema. Become tool arguments sent in the URL query string. |
body | No | — | JSON-body fields → field schema. Become tool arguments sent in the request body. |
headers | No | — | Static HTTP headers. Values support ${SETTING} placeholders. Not exposed as tool arguments. |
* name must come from somewhere: either in options or from the capability's own name. If neither is set, the tool won't build.
Field schema (for params and body)¶
Each entry under params or body describes one argument the model can fill in:
{
"param_name": {
"type": "string",
"description": "What this parameter does",
"required": true,
"default": "optional default value"
}
}
| Attribute | Values | Notes |
|---|---|---|
type | string, integer, number, boolean | Unknown types default to string. |
description | string | Shown to the model — describe the argument well. |
required | bool (default false) | Required arguments have no default; optional ones are nullable. |
default | any | Used for optional arguments when the model omits them. |
Field names must be unique across params and body
A single field name cannot appear in both params and body. Overlapping names are rejected — rename the duplicate so each maps unambiguously.
Name and description fallback¶
So you don't repeat yourself, when name/description are omitted from options:
- name → the capability's name, slugified into a valid function name. For example, a capability named "Open-Meteo Weather" becomes the tool
open_meteo_weather. - description → the capability's description; if that's also empty →
"Call the {tool_name} API".
Values in options always override these fallbacks.
How a call works¶
When the model calls the tool:
- Arguments are split — those declared in
paramsgo to the query string; those inbodygo to the JSON body. Empty values are dropped. - The URL is re-resolved and re-validated for safety (see Security).
- An HTTPS request is made with a 30-second timeout.
- On success, the response body is returned to the model as text.
Errors the model sees¶
These failures are returned to the model as text (so it can react), not raised as errors:
| Condition | Returned to the model |
|---|---|
| URL fails safety validation | API request blocked: {detail} |
| Non-2xx HTTP status | API error: HTTP {status_code} |
| Network failure, timeout, etc. | API request failed: {detail} |
Build-time problems (missing url/name, a bad method, overlapping params/body, or an unresolved placeholder) instead prevent the tool from being created. The capability is skipped and the issue is logged — the agent simply won't have that tool.
Settings placeholders (${SETTING_NAME})¶
Never hard-code secrets like API keys or tokens. Any string value in options can contain ${SETTING_NAME} placeholders, resolved at build time from your user/group settings.
- The name must be word characters (letters, digits, underscore):
\${WEATHER_API_KEY}. - Example:
"Authorization": "Bearer ${WEATHER_API_KEY}". - Placeholders are resolved in the
urlandheaders. - If a referenced setting is missing or empty, the tool fails to build and is skipped (logged). Define the setting before enabling the capability.
You configure settings on the Settings page (or via the admin API):
The value is then available as ${WEATHER_API_KEY} in any capability's options.
Dot-notation keys¶
The capability editor stores options as flat name/value pairs and can't natively express nested structures. To get around this, any key containing a dot is expanded into nested objects:
Rules:
- Keys without a dot are kept as-is.
- Multiple dotted keys sharing a prefix are merged under the same parent.
- Dotted keys merge into any already-nested value at the same path, so existing nested JSON keeps working — you can mix styles freely.
Tip
If your editor lets you enter JSON objects directly, you can nest without dot-notation. Dot-notation is just the escape hatch for flat key/value editors.
Security¶
API capabilities are guarded to prevent them from reaching internal services:
- HTTPS only.
http://URLs are rejected. - SSRF protection. Before each request the hostname is resolved and every resolved IP is checked. Requests are blocked if the target resolves to a private, loopback, link-local, reserved, multicast, or carrier-grade-NAT (
100.64.0.0/10) address. This blocks attempts to reach internal services or cloud metadata endpoints (such as169.254.169.254). - The original hostname is preserved for the request (so TLS/SNI stays correct); the validated IP is used only for connection targeting.
Examples¶
All three examples use real, live endpoints so you can adapt them directly.
GET with an API key — recent news (NewsAPI)¶
When you'd use this: give a research or briefing agent the ability to pull recent articles on demand. NewsAPI takes its key in an X-Api-Key header, so the key stays in headers (a secret) and never becomes a model-visible argument.
{
"name": "Search News",
"type": "api",
"options": {
"name": "search_news",
"description": "Search recent news articles by keyword.",
"method": "GET",
"url": "https://newsapi.org/v2/everything",
"params": {
"q": { "type": "string", "description": "Search keywords or phrase", "required": true },
"sortBy": { "type": "string", "description": "relevancy, popularity, or publishedAt", "required": false, "default": "publishedAt" },
"language": { "type": "string", "description": "2-letter language code, e.g. 'en'", "required": false, "default": "en" }
},
"headers": {
"X-Api-Key": "${NEWSAPI_KEY}"
}
}
}
POST with a JSON body — send an email (Resend)¶
When you'd use this: let an agent send a transactional email — a summary, an alert, a follow-up — at the end of a workflow. The API key lives in a header; the email fields become typed tool arguments the model fills in.
{
"name": "Send Email",
"type": "api",
"options": {
"name": "send_email",
"description": "Send an email via Resend.",
"method": "POST",
"url": "https://api.resend.com/emails",
"body": {
"from": { "type": "string", "description": "Verified sender, e.g. 'agent@yourdomain.com'", "required": true },
"to": { "type": "string", "description": "Recipient email address", "required": true },
"subject": { "type": "string", "description": "Email subject line", "required": true },
"html": { "type": "string", "description": "HTML body of the email", "required": true }
},
"headers": {
"Authorization": "Bearer ${RESEND_API_KEY}",
"Content-Type": "application/json"
}
}
}
No auth, using the flat editor — weather forecast (Open-Meteo)¶
When you'd use this: a genuinely free, key-less API — great for a first capability. Open-Meteo needs no sign-up. This example also shows the flat editor: name/description are left out and fall back to the capability — named "Open-Meteo Weather", it becomes the tool open_meteo_weather.
method = GET
url = https://api.open-meteo.com/v1/forecast
params.latitude.type = number
params.latitude.required = true
params.longitude.type = number
params.longitude.required = true
params.current.type = string
params.current.default = temperature_2m
Quick reference¶
Minimal API capability:
(method defaults to GET; name can be omitted if the capability name is set.)
Rules to remember:
- HTTPS only; methods
GET/POST/PUT/PATCH; no public/internal IPs. - A field name can't appear in both
paramsandbody. - Secrets →
${SETTING_NAME}placeholders, defined in settings first. - Nested config in a flat editor → dot-notation keys (
params.x.type).
Related Topics¶
- Capabilities — what capabilities are and how they're used
- MCP Capabilities — connect a remote MCP server instead
- Working with AI Agents — assigning capabilities to an agent