OpenAPI Integrations
Connect Martha to any REST API by importing its OpenAPI specification. Martha extracts endpoints as callable functions, handles authentication, and makes them available to agents and workflows.
Quick Start
# Preview what will be imported (dry-run is default)
martha integrations import-openapi \
--source https://api.example.com/openapi.json \
--name my-api \
--prefix myapi_
# Import for real with authentication
martha integrations import-openapi \
--source https://api.example.com/openapi.json \
--name my-api \
--prefix myapi_ \
--auth-scheme apiKey \
--auth-header X-Api-Key \
--auth-value 'your-api-key' \
--no-dry-runAuthentication
Auth is set at import time and applied to all imported functions. Supported schemes:
| Scheme | Header | Value format |
|---|---|---|
apiKey | Custom (e.g., X-Api-Key) | Raw key value |
bearer | Authorization | Token (auto-prefixed with Bearer ) |
basic | Authorization | user:pass (auto-encoded to base64) |
CLI flags
| Flag | Description |
|---|---|
--auth-scheme | apiKey, bearer, basic, oauth2, none |
--auth-header | Header name (default: Authorization) |
--auth-value | Credential value |
--auth-query-param | For API keys passed as query parameters |
--auth-credential-source | Reference key for credentials stored in your secret store |
Credential priority at execution time
When a function is called, credentials are resolved in this order:
- Session-level (per chat session, highest priority)
- Client-level (shared across sessions for a client)
- Function definition default (from import-time
--auth-value)
Store credentials at the client level for production use:
# Store credential for a client
POST /clients/{client_id}/credentials
{
"service_name": "my-api",
"value": "your-api-key",
"header": "X-Api-Key"
}How parameters work
Martha maps OpenAPI parameters to function parameters:
| OpenAPI location | Martha location | At execution time |
|---|---|---|
in: path | location: path | Substituted into URL template ({param}) |
in: query | location: query | Added to query string |
requestBody.properties.* | location: body | Sent as JSON body fields |
For free-form POST bodies (schemas with additionalProperties: true and no properties), any parameter the agent passes that isn't a path or query param is automatically included in the request body.
Post-import setup
After importing, grant functions to clients and agents:
# List imported functions
martha functions list --source my-api
# Grant all to a client
martha functions list --limit 200 --json | \
python3 -c "import json,sys
for f in json.load(sys.stdin):
if f['name'].startswith('myapi_'): print(f['name'])" | \
while read name; do
martha clients grant my-client function "$name"
done
# Add to an agent
martha agents add-function my-agent myapi_list_items
martha agents add-function my-agent myapi_create_itemEnriching function descriptions
Imported functions get their descriptions from the OpenAPI spec's summary field. For better agent behavior, update descriptions with domain context:
martha functions update myapi_create_item -f - <<'EOF'
description: >
Create an item in the inventory. Pass name (required), category,
and quantity as parameters. For supplier references, use
supplier_id=<uuid>. Items are created in "draft" status by default.
EOFGood descriptions include:
- What the endpoint does in domain terms
- Required vs optional parameters
- Relationship patterns (how to reference related entities)
- Default behaviors and filters to apply
- IDs of well-known resources (collections, databases)
Managing specs
# List imported specs
martha integrations specs
# Re-sync a spec (picks up new endpoints)
martha integrations sync <spec-id>
# Force re-sync even if hash matches
martha integrations sync <spec-id> --forcePartial specs
Not every API publishes an OpenAPI spec. You can write a partial spec covering just the endpoints you need:
openapi: "3.0.3"
info:
title: My API (partial)
version: "1.0"
servers:
- url: https://api.example.com
security:
- apiKey: []
components:
securitySchemes:
apiKey:
type: apiKey
in: header
name: X-Api-Key
paths:
/api/items:
get:
operationId: listItems
summary: List all items
parameters:
- name: limit
in: query
schema:
type: integer
responses:
"200":
description: List of items
post:
operationId: createItem
summary: Create a new item
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name:
type: string
category:
type: string
responses:
"201":
description: Created itemHost it (e.g., as a GitHub gist) and import:
martha integrations import-openapi \
--source https://gist.githubusercontent.com/.../spec.yaml \
--name my-api --prefix myapi_ \
--auth-scheme apiKey --auth-header X-Api-Key \
--auth-value 'key' --no-dry-runTroubleshooting
"Entity type not found" or "Unknown field" on POST
The function handler may be sending path parameters in the request body. Check:
martha functions get myapi_create_item --json | python3 -c "
import json, sys
params = json.load(sys.stdin).get('definition',{}).get('parameters',{})
for k, v in params.items():
print(f'{k}: location={v.get(\"location\")}')"Path parameters should show location=path. If they show location=None, the spec was imported with an older version of the import service -- reimport.
Functions not showing body parameters
If a POST endpoint's body fields don't appear in the function parameters, the requestBody schema may use $ref that didn't resolve, or the schema has additionalProperties: true with no properties. In the latter case, this is expected -- the agent can pass any field and it will be routed to the body automatically.
Auth errors (401/403)
Check the stored auth config:
martha functions get myapi_list_items --json | python3 -c "
import json, sys
auth = json.load(sys.stdin).get('definition',{}).get('auth',{})
print(json.dumps(auth, indent=2))"If value contains ${VAR}, the variable must exist as an environment variable in the running deployment. For reliability, use a literal credential value or set the credential at the connection level so it's resolved from the secret store at call time.