> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trymaitai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API to Agent

> Turn an API into a structured Agent by importing endpoints as API Call actions, organizing them into domain subagents, and encoding the API docs as instructions.

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” are encoded into the agent's **flow step prompts** 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):

| Subagent               | Example endpoints that become API Actions                                                              |
| ---------------------- | ------------------------------------------------------------------------------------------------------ |
| Stripe Payments Agent  | `POST /v1/payment_intents`, `GET /v1/payment_intents/{id}`, `POST /v1/refunds`, `GET /v1/charges/{id}` |
| Stripe Customers Agent | `POST /v1/customers`, `GET /v1/customers/{id}`, `GET /v1/customers`, `POST /v1/customers/{id}`         |
| Stripe Invoices Agent  | `GET /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](/build/agents/capabilities/subagent)

## 2) Create the parent agent + domain subagents

### Create the parent (“Stripe Agent”)

1. Go to **Forge > Agents > Create Agent**.
2. Set:
   * **Name**: “Stripe Agent”
   * **Description**: “Routes requests across Stripe domains and returns user-facing answers.”
   * **Execution Mode**: **Reasoning**: the parent needs to sequence calls, delegate to domain subagents, and wait on webhooks
   * **Base URL** (optional): default host used by API actions (often your Stripe proxy / gateway)

See: [Create Agent](/build/agents/create_agent) · [Execution Mode](/build/agents/execution_mode)

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

1. Go to **Forge > Agents > Create 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**, then 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 to actions)

This is the “endpoint-to-action” step: each selected OpenAPI operation becomes one **API Call** action.

### Bulk Import (recommended for “every endpoint becomes an 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 **Capabilities > Add Capability > API 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](/build/agents/capabilities/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](/build/agents/capabilities/webhook)

### Add a "Webhook Creation" capability to the Payments subagent

1. Open **Stripe Payments Agent**.
2. Go to **Capabilities > Add Capability > Webhook 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

<Note>
  The registration endpoint and payload structure are **automatically inferred** by the LLM based on context. You only need to provide authentication credentials.
</Note>

**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, which 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, then **your webhook handler** (verify), then 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:

```json theme={null}
{
  "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:

```bash theme={null}
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 State: 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 the **State** tab.
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 State](/build/agents/agent_state)

## 7) “Load the API docs” into the flow step prompts

This is the step that makes the agent behave like it “understands the docs”. Open **Configuration** on the parent agent and customize the relevant [flow steps](/build/agents/agent_flow):

### Orchestrate step

Owns delegation and sequencing. Add guidance like:

* Route “payment”, “charge”, “refund” to **Stripe Payments Agent**
* Route “customer”, “user”, “account” to **Stripe Customers Agent**
* Route “invoice”, “bill”, “statement” to **Stripe Invoices Agent**
* Required inputs per workflow (what IDs must exist before calling an endpoint)
* Happy-path sequences (e.g., lookup customer, list invoices, then finalize invoice)
* Guardrails (never create resources without explicit user confirmation; if required IDs are missing, ask a clarifying question instead of guessing)
* Async lifecycles (e.g., “create PaymentIntent, wait for event, then fetch final status”)

### Process step

Owns result interpretation and state updates. Add guidance like:

* What matters in each API response (which fields are findings worth keeping)
* What to store in state for later steps (IDs, statuses, amounts)
* How to treat API errors (what a 4xx vs 5xx means for the task)

### Respond step

Owns the user-facing answer. Add guidance like:

* How to summarize responses for the user (what fields matter)
* How to translate API errors into user-facing guidance
* Tone and formatting policy

See: [Agent Flow Steps](/build/agents/agent_flow)

## 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)
   * add more “API doc” guidance to the Orchestrate/Process step prompts (better sequencing + summaries)
   * narrow schemas so actions can’t be called with ambiguous inputs

See: [Agent Flow Steps](/build/agents/agent_flow)
