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

# Wrap a REST API in a Skill

> When there is no native Connection for a system but it has an HTTP API, package the call as a script inside a custom Skill. The Agent decides what to ask; the script makes the request the same way every time.

Sometimes the system an Agent needs is not in the [Connections catalog](/user-guide/connections/available-connections) — an internal ERP, a legacy service, a departmental tool — but it does expose an HTTP API. You do not have to wait for a native Connection. If the API is a handful of endpoints and you can authenticate with a token or username and password, package the call as a script inside a [custom Skill](/user-guide/skills/creating-custom-skills). The Agent extracts the parameters and reads the result; the script builds the request, sends it, and handles the errors the same way on every Run.

The principle is the same one behind putting an exact calculation in a Skill: keep the judgment in the Agent, and move the exact, repeatable mechanics into a script. Here the mechanics are an HTTP call instead of a calculation.

## When to Reach for This

Wrap an API in a Skill when all of these hold:

* **There is no native Connection** for the system, and you would otherwise ask the Agent to "figure out the API" from prose.
* **The surface is small** — a few read endpoints, one authentication scheme. You are exposing specific questions ("look up the payment terms for this customer"), not the whole API.
* **You can supply credentials as a Secret**, so the script reads them from the environment and never sees them in an AOP or a prompt.

If the surface is large, several teams need it, or you want it to appear as a first-class Connection with its own setup screen, build a [custom MCP server](/mcp/custom-mcp-servers) and connect it as a [Custom MCP Connection](/user-guide/connections/available-connections/custom-mcp) instead. The Skill-with-a-script route is the fast path for a narrow, internal API — no server to host, no deployment, just files attached to an Agent.

## The Pattern

A custom Skill is a package of files: the instructions (`SKILL.md`) plus anything they reference. For an API wrapper, the instructions walk the Agent through four steps, and the request itself lives in a script the instructions tell it to run.

```mermaid theme={"dark"}
flowchart LR
    A[Agent reads the request] --> B[Extract and validate<br/>the parameters]
    B --> C[Script reads the Secret,<br/>builds and sends the call]
    C --> D[Agent formats the result<br/>and acts on it]
```

The division of labor mirrors the math pattern:

* **The Agent** (via the AOP and the Skill instructions): understands what was asked, pulls out the parameters, runs the script with those values, and presents the response — deciding what to do with it.
* **The script**: reads the credentials from the environment, constructs the request (auth header, query, filters), sends it, and turns HTTP status codes into clear, actionable messages. No judgment, no variation between Runs.

A worked example: a manufacturer needed its Agents to look up order payment terms from an internal ERP that exposed a read-only OData endpoint but had no native Connection. Rather than teaching every AOP the query syntax, the team shipped one Skill. The Agent extracts the customer number and product hierarchy from the user's request; the script zero-pads the customer number to the format the ERP expects, assembles the OData filter, sends an authenticated GET, and prints the matching order lines. The Agent then groups the results and offers a CSV export. The query syntax lives in exactly one place.

## Structure the Skill in Four Steps

Write the `SKILL.md` so the Agent follows the same sequence every time.

<Steps>
  <Step title="Check credentials first" icon="key">
    Open with a short script that reads the required environment variables and stops with a clear message if any are missing — "the *System X* Secret is not attached to this Agent" — so a misconfiguration fails obviously instead of surfacing as a confusing auth error later. Store the credentials as a [Secret](/user-guide/resources/secret-management) and attach it to the Agent; never put them in the AOP, the Skill, or a prompt.
  </Step>

  <Step title="Extract and validate the parameters" icon="list-checks">
    List the inputs the call needs in a table — name, whether it is required, its default, and how to recognize it in the user's request. Tell the Agent to ask for anything missing or ambiguous rather than guessing. This is the one step where the Agent's judgment matters; keep it explicit.
  </Step>

  <Step title="Call the API in a script" icon="code">
    Put the request in a fenced script block: read the Secret from the environment, build the auth header, assemble the query from the validated parameters, send it with a timeout, and parse the response. The Agent substitutes the extracted values and runs it — it does not compose the URL from memory.
  </Step>

  <Step title="Present the result in a fixed shape" icon="table">
    Specify exactly how to format the response — a summary, then a detail table, with a rule for large result sets (show the first rows, offer a full CSV export). A defined output shape keeps every Run's answer consistent and reviewable.
  </Step>
</Steps>

## Make It Robust and Extensible

Two tables in the Skill do most of the work of keeping it reliable and cheap to change:

* **Map every error to an action.** Turn each HTTP status into a message that tells the user what to do, not just what broke — `401` means check the Secret; a `403` signals an access problem whose exact cause depends on the API (the endpoint not being enabled, or the credential lacking the right permission or scope); a connection error means check the network path. Base each mapping on the target API's own documented error semantics. The Agent relays a fix, not a stack trace.
* **Document the query surface as a reference table.** List the filters or fields the API accepts and their syntax. When someone needs a new filter or a sibling endpoint, they adapt the script from the table — no rewrite, and often no code change at all.

<Tip>
  Put a line like this in the instructions, next to the call: "Run the script to make the request. Do not construct the URL or guess the query syntax yourself." Without it, the Agent will happily improvise a request the day the API returns something unexpected — and improvised requests are exactly what this pattern exists to prevent.
</Tip>

## Why Not the Alternatives

| Alternative                              | What goes wrong                                                                                                                |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| The AOP describes the API in prose       | The Agent composes a slightly different request across Runs; a malformed query fails quietly or returns the wrong rows         |
| The Agent writes throwaway code each Run | Every Run reinvents the auth and query logic — unversioned, untested, and drifting                                             |
| Each Agent embeds its own copy           | Three Agents, three request formats; an endpoint change means three edits                                                      |
| Build a custom MCP server                | The right move once the surface grows or several teams need it — but heavier than a narrow, internal, read-mostly API warrants |

## What You Get

* **One place for the request.** Auth, endpoint, and query syntax live in a single Skill. A change is one edit, propagated to every Agent the Skill is attached to.
* **Consistency across Runs.** Identical inputs produce an identical request every time — the Skill removes the variability. What comes back still reflects the API's current state; the request is repeatable, not the data behind it.
* **Credentials stay out of instructions.** The script reads them from the environment; the Secret is managed and attached separately, never pasted into an AOP or prompt.
* **Cheap to extend.** New filters and sibling endpoints come from the reference table, often without touching code.

## When Not To

* **A native Connection already exists** — use it. This pattern is for systems the catalog does not cover.
* **The API surface is broad, or several teams need it** — invest in a [custom MCP server](/mcp/building-mcp-servers) so it becomes a proper, reusable Connection.
* **The work is write-heavy or high-risk** (creating records, moving money). A read-only lookup is the ideal first candidate; gate anything that acts outward behind [human-in-the-loop review](/user-guide/assignment-features/human-in-the-loop) and treat a Connection as the more durable home.

## Related

<CardGroup cols={2}>
  <Card title="Creating Custom Skills" icon="package" href="/user-guide/skills/creating-custom-skills">
    How to package instructions, scripts, and reference files into a Skill.
  </Card>

  <Card title="Skills" icon="book-open" href="/user-guide/skills/skills-overview">
    How Skills attach to Agents and load during a Run.
  </Card>

  <Card title="Custom MCP Connection" icon="plug" href="/user-guide/connections/available-connections/custom-mcp">
    Graduate a wrapped API into a first-class Connection when the surface grows.
  </Card>

  <Card title="Secret Management" icon="key" href="/user-guide/resources/secret-management">
    Store the API credentials as a Secret and attach them to the Agent.
  </Card>
</CardGroup>
