Skip to content

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

bash
# 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-run

Authentication

Auth is set at import time and applied to all imported functions. Supported schemes:

SchemeHeaderValue format
apiKeyCustom (e.g., X-Api-Key)Raw key value
bearerAuthorizationToken (auto-prefixed with Bearer )
basicAuthorizationuser:pass (auto-encoded to base64)

CLI flags

FlagDescription
--auth-schemeapiKey, bearer, basic, oauth2, none
--auth-headerHeader name (default: Authorization)
--auth-valueCredential value
--auth-query-paramFor API keys passed as query parameters
--auth-credential-sourceVault lookup key for dynamic credentials

Credential priority at execution time

When a function is called, credentials are resolved in this order:

  1. Session-level (per chat session, highest priority)
  2. Client-level (shared across sessions for a client)
  3. Function definition default (from import-time --auth-value)

Store credentials at the client level for production use:

bash
# 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 locationMartha locationAt execution time
in: pathlocation: pathSubstituted into URL template ({param})
in: querylocation: queryAdded to query string
requestBody.properties.*location: bodySent 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:

bash
# 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_item

Enriching function descriptions

Imported functions get their descriptions from the OpenAPI spec's summary field. For better agent behavior, update descriptions with domain context:

bash
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.
EOF

Good 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

bash
# 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> --force

Partial specs

Not every API publishes an OpenAPI spec. You can write a partial spec covering just the endpoints you need:

yaml
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 item

Host it (e.g., as a GitHub gist) and import:

bash
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-run

Troubleshooting

"Entity type not found" or "Unknown field" on POST

The function handler may be sending path parameters in the request body. Check:

bash
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:

bash
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 env var must exist on the production server. For reliability, use the actual credential value or store in Vault.

Martha is built by aiaiai-pt.