Skip to main content
This recipe shows how to take an existing API and build a single Agent entrypoint where:
  • Each endpoint becomes a Capability (an API Call action)
  • Endpoints are grouped into a domain subagent tree (Payments, Customers, Invoices, etc.)
  • Your “API docs” become Orchestration / Strategy / Processing instructions so the agent can sequence calls reliably
The outcome is an “integration without reading the docs”: users can point requests at the parent agent, and the agent knows which endpoints to call and in what order.

1) Choose a subagent tree (example: “Stripe Agent”)

Before importing anything, decide how you want to divide the API into domains. For a Stripe-style API, a common tree is:
  • Parent: “Stripe Agent”
    • Routes requests to the right domain agent
    • Produces user-facing answers (and asks clarifying questions when inputs are missing)
  • Children (subagents):
    • “Stripe Payments Agent” (payments + refunds)
    • “Stripe Customers Agent” (customer lookup + updates)
    • “Stripe Invoices Agent” (invoice lifecycle)
Each subagent should “own” the endpoints for its domain. Example mapping (illustrative):
SubagentExample endpoints that become API Actions
Stripe Payments AgentPOST /v1/payment_intents, GET /v1/payment_intents/{id}, POST /v1/refunds, GET /v1/charges/{id}
Stripe Customers AgentPOST /v1/customers, GET /v1/customers/{id}, GET /v1/customers, POST /v1/customers/{id}
Stripe Invoices AgentGET /v1/invoices, GET /v1/invoices/{id}, POST /v1/invoices, POST /v1/invoices/{id}/finalize
This keeps each subagent’s toolset smaller and makes routing more reliable. See: Subagent

2) Create the parent agent + domain subagents

Create the parent (“Stripe Agent”)

  1. Go to Forge > AgentsCreate Agent.
  2. Set:
    • Name: “Stripe Agent”
    • Description: “Routes requests across Stripe domains and returns user-facing answers.”
    • Base URL (optional): default host used by API actions (often your Stripe proxy / gateway)
See: Create Agent

Create one agent per domain (Payments, Customers, Invoices)

  1. Go to Forge > AgentsCreate Agent (repeat for each domain).
  2. Keep descriptions crisp (they are used for routing).

Attach subagents under the parent

  1. Open the parent agent.
  2. Go to Capabilities.
  3. Click Add Capability → choose Subagent.
  4. Add your domain agents (Payments, Customers, Invoices).
Tip: keep each subagent’s description crisp — the parent router uses these descriptions to decide where to delegate.

3) Capabilities: convert endpoints into API Call actions (OpenAPI → actions)

This is the “endpoint-to-action” step: each selected OpenAPI operation becomes one API Call action. Do this once per subagent, selecting only the endpoints for that domain:
  1. Open a domain subagent (e.g., “Stripe Payments Agent”).
  2. Go to Capabilities.
  3. Click Bulk Import.
  4. Paste your OpenAPI spec (JSON or YAML).
  5. Deselect any endpoints that don’t belong to this subagent’s domain.
  6. Optionally rename action names/descriptions (recommended for readability).
  7. Click Import.
This creates one API Call action per selected OpenAPI operation, including:
  • Path + query parameters
  • JSON request body schema (when present)
  • JSON response schemas (per status code, when present)

Single-action Import (good for incremental additions)

  1. Open the agent.
  2. Go to CapabilitiesAdd CapabilityAPI Call.
  3. In the API action editor, click Import and paste an OpenAPI spec.
  4. Select the operation to use and import it.
See: API Action

4) Capabilities: add webhook-based lifecycle handling (PaymentIntent example)

Some APIs are inherently asynchronous. For Stripe PaymentIntents, “create” and “final status” are often separated by an event (payment_intent.succeeded, payment_intent.payment_failed, etc.). Maitai supports this using a Webhook Creation capability that:
  • registers a per-session webhook callback with Maitai’s hooks service and returns a unique webhook_url (e.g., https://hooks.trymaitai.ai/agent/<key>)
  • automatically infers where and how to register the webhook based on conversation context
  • sends the registration request to the appropriate external service (e.g., Stripe, Shopify)
  • returns WAITING_WEBHOOK until an external system POSTs an event payload to that webhook_url
When a payload is POSTed to the webhook_url, Maitai’s hooks service looks up the webhook key and routes the payload to the correct agent + session, then resumes execution. See: Webhook

Add a “Webhook Creation” capability to the Payments subagent

  1. Open Stripe Payments Agent.
  2. Go to CapabilitiesAdd CapabilityWebhook Creation.
  3. Invocation Mode is automatically set to Foreground (webhooks must pause execution to wait for callbacks).
  4. Configure authentication and optional settings:
    • Authentication: Add your Stripe API key (Bearer token, API key, or Basic auth)
    • Headers (optional): Additional headers needed for registration
    • Timeout: How long to wait for the webhook callback (default: 10 minutes)
That’s it! When the agent invokes this capability, Maitai will:
  1. Create a unique webhook URL
  2. Analyze the conversation context (user request, capability description, recent API calls)
  3. Intelligently infer the registration endpoint and payload structure (e.g., Stripe’s /v1/webhook_endpoints)
  4. Add your configured authentication and headers
  5. Make the registration HTTP call
  6. Wait for the external service to call back
The registration endpoint and payload structure are automatically inferred by the LLM based on context. You only need to provide authentication credentials.
Example scenario: User: “Create a payment intent for $50 and let me know when it’s confirmed” Agent flow:
  1. Calls create_payment_intent API action → creates PaymentIntent pi_123
  2. Invokes webhook capability
  3. LLM infers from context:
    • Service: Stripe
    • Endpoint: https://api.stripe.com/v1/webhook_endpoints
    • Payload: {"url": "https://hooks.trymaitai.ai/agent/abc123", "enabled_events": ["payment_intent.succeeded"]}
  4. System adds your configured Stripe API key to the request
  5. Registration call succeeds
  6. Agent waits for Stripe to call the webhook
  7. Stripe calls webhook when payment succeeds
  8. Agent resumes and responds to user
If registration fails (e.g., invalid credentials), the agent returns an error immediately instead of waiting.

What should call back to Maitai?

Maitai’s agent webhook endpoint (the webhook_url on hooks.trymaitai.ai) does not verify provider signatures (like Stripe’s Stripe-Signature).
  • If you need signature verification, use: Stripe → your webhook handler (verify) → Maitai webhook_url (forward)
  • If you accept the risk (not recommended), you can configure Stripe to call the webhook_url directly.
For testing, you can POST a payload to the webhook_url the agent generated. Example:
{
  "provider": "stripe",
  "event_type": "payment_intent.succeeded",
  "payment_intent_id": "pi_123",
  "customer_id": "cus_456",
  "amount": 2000,
  "currency": "usd"
}
If you want to simulate the callback manually:
curl --request POST \
  --url "$WEBHOOK_URL" \
  --header "Content-Type: application/json" \
  --data '{"provider":"stripe","event_type":"payment_intent.succeeded","payment_intent_id":"pi_123","customer_id":"cus_456","amount":2000,"currency":"usd"}'

5) Make capabilities usable (naming, auth, foreground/background, schemas)

After import, open actions and confirm the config is correct:
  • Invocation Mode
    • Foreground: results are user-facing (used in the agent’s response)
    • Background: results are stored in context only (not shown to the user)
  • Response Type (API Call actions only)
    • Real: call the live API
    • Mock: return predefined responses (useful to prototype before auth is ready)
  • Auth / Headers
    • bulk import defaults auth to “none”; set the auth scheme your API needs
  • Request/Response schema
    • keep request schemas tight so the agent doesn’t “invent” parameters
Tip: For large APIs, naming consistency matters. Prefer action names like stripe_create_payment_intent, stripe_get_customer, stripe_finalize_invoice.

6) Agent Form: define the state the agent should maintain

When an API is involved, state is often the difference between a clean flow and a confusing one.
  1. Open the agent.
  2. Go to ConfigurationAgent Form.
  3. Add fields like:
    • customer_id
    • payment_intent_id
    • invoice_id
    • last_refund_id
  4. Set Read/Write scope based on which subagents should be able to see/update the field.
See: Agent Form

7) “Load the API docs” into instructions (Routing + Strategy + Processing)

This is the step that makes the agent behave like it “understands the docs”.

Orchestration Instructions (Configuration → Routing)

These live in the parent agent and should:
  • route the request to the right domain subagent
  • enforce sequencing guardrails (ask clarifying questions vs guessing)
Example (parent “Stripe Agent”):
  • Route “payment”, “charge”, “refund” → Stripe Payments Agent
  • Route “customer”, “user”, “account” → Stripe Customers Agent
  • Route “invoice”, “bill”, “statement” → Stripe Invoices Agent
  • If required IDs are missing (customer, payment_intent, invoice), ask a clarifying question instead of guessing

Strategy Instructions (Configuration → Instructions → Strategy Instructions)

Use this to paste the “how to use the API” guidance:
  • Required inputs per workflow (what IDs must exist before calling an endpoint)
  • Happy-path sequences (e.g., lookup customer → list invoices → finalize invoice)
  • Guardrails (never create resources without explicit user confirmation)
  • Error handling expectations (what to do on 4xx/5xx)
  • Async lifecycles (e.g., “create PaymentIntent → wait for event → fetch final status”)

Processing Instructions (Configuration → Instructions → Processing Instructions)

Use this to define:
  • How to summarize responses for the user (what fields matter)
  • What to store in state for later steps (IDs, statuses, amounts)
  • How to translate API errors into user-facing guidance
See: Orchestration, Special Instructions

8) Test in Studio (including webhook lifecycle)

  1. Go to Forge > Studio.
  2. Select the parent agent (e.g., “Stripe Agent”).
  3. Try prompts that force cross-domain behavior:
    • “Refund the last payment for customer cus_...
    • “Create an invoice for customer cus_... for $200 and finalize it”
    • “Which invoices are past due for customer cus_...?”
  4. Test an async PaymentIntent flow:
    • “Create a $20 PaymentIntent for customer cus_... and tell me when it succeeds.”
    • You should see the agent return WAITING_WEBHOOK plus a Webhook URL.
    • When your system (or a test script) POSTs the event payload to that webhook URL, Maitai will resume the agent and continue execution.
  5. Iterate:
    • tighten subagent descriptions (better routing)
    • paste more “API doc” guidance into Strategy/Processing Instructions (better sequencing + summaries)
    • narrow schemas so actions can’t be called with ambiguous inputs
See: Special Instructions