---
title: "Routes on Ouro"
description: "Callable API endpoints and the execution records they create"
date: "2026-05-23"
last_updated: "2026-05-23"
---

A **route** is one HTTP endpoint on Ouro: a method, path, parameters, and
response shape. Routes live under a parent [service](/docs/concepts/services)
that shares a base URL and authentication.

Every time someone runs a route from the UI, [Python SDK](/docs/developers/api/python),
or [MCP](/docs/developers/mcp), Ouro stores an **action**: the request, response,
status, and any assets created or consumed. Routes are what you call; actions are
the execution records you poll, chain, and embed in posts.

<IconLink
  icon="water"
  href="/docs/concepts/services"
  title="Services"
  description="Register an API and import its OpenAPI spec"
/>

## How routes are created

Most routes arrive automatically when you import an OpenAPI spec on service creation.
The platform parses each path and operation into a Route asset with in-product docs
derived from your descriptions.

You can also add or edit routes in the UI from a service's route table, or with
`ouro.routes.create` / `ouro.routes.update` in the Python SDK.

Each route includes:

- **Method and path** - e.g. `POST /predict`
- **Request schema** - body, query, and header parameters from the spec
- **Response schema** - what callers should expect back
- **Asset identifier** - `creator/name-method` in URLs; stable UUIDs are safer for scripts

## Typed inputs and outputs

Routes can declare expected **input** and **output** assets so Ouro validates
compatibility and wires IDs for you. This is useful for pipelines such as
file in, dataset out.

Declare keyed assets in OpenAPI with `x-ouro-input-assets` and
`x-ouro-output-assets`. See the [route input and output assets guide](/guides/route-input-output-assets)
for YAML and request examples.

Quick rules:

- Use `input_filter` for broad types (`audio`, `image`, `video`)
- Use `input_file_extensions` for exact formats (`xy`, `pdf`, etc.) without leading dots
- Mark one output with `primary: true` when a route mainly produces a single asset

## Running a route

From the route page, fill inputs and click run. In code:

```python showLineNumbers
route = ouro.routes.retrieve(route_id)
action = route.execute(body={"composition": "Fe2Ni"})
result = action.final_data
```

MCP: `execute_route(route_id, body={...})` returns an `action_id` when you need to poll.

Routes can be **monetized** like other assets; you are charged only on successful
paid runs. See [How to monetize APIs](/guides/how-to-sell-apis-on-ouro).

## Actions

An action is the durable record of one route execution.

### What an action contains

- **Status** - `queued`, `in-progress`, `success`, `error`, or `timed-out`
- **Request body and parameters** - what was sent to the upstream API
- **Response data** - parsed result (`final_data` in the Python SDK)
- **Input and output assets** - files, datasets, or posts consumed or created, keyed by declared names
- **Action ID** - for polling, logs, and [extended markdown](/docs/concepts/extended-markdown) embeds

On the route page, the actions tab lists past runs (yours by default; admins may see more).

### Sync vs async runs

**Short requests** finish in one call; `final_data` is populated on the returned action.

**Long-running APIs** should accept the job, return `202 Accepted`, and POST results to the
`ouro-webhook-url` header Ouro sends on each request. While the action is running, poll with
`ouro.routes.retrieve_action(action_id)` or MCP `get_action`.

| Header                                     | Purpose                                   |
| ------------------------------------------ | ----------------------------------------- |
| `ouro-webhook-url`                         | Where your worker POSTs the final result  |
| `ouro-webhook-token`                       | Authenticate webhook callbacks            |
| `ouro-action-id`                           | Correlate logs and progress with this run |
| `ouro-route-id`                            | Route being executed                      |
| `ouro-route-org-id` / `ouro-route-team-id` | Where output assets should be created     |

See [Building long-running APIs](/guides/long-running-apis) for the full webhook pattern.

### Chaining routes

Pass one action's outputs into the next route:

```python showLineNumbers
gen = generation_route.execute(body={"composition": "Fe2Ni"})
file_id = gen.final_data["file"]["id"]

pred = prediction_route.execute(input_assets={"file": file_id})
```

Prefer **named** `input_assets` and `output_assets` keys — they are the
canonical declaration shape. The legacy `input_type` / `output_type` columns
are kept synchronized as a primary projection for older clients, but new
code should read and write the plural keyed maps. Output asset creation only
uses declared `output_assets`.

### Listing and inspecting actions

```python showLineNumbers
route = ouro.routes.retrieve(route_id)
actions = route.read_actions()  # your runs by default
action = ouro.routes.retrieve_action(action_id)
```

### Sharing results in posts

Embed the route with an action pinned so readers see status, logs, and outputs inline.
See [Extended markdown: route executions](/docs/concepts/extended-markdown#referencing-route-executions).

## Discovery and composition

- **`get_compatible_routes`** (MCP) and the product UI surface routes that accept a given file or dataset
- Chain routes using `input_assets` from a prior action's outputs
- Link related files, datasets, and posts on the route so others have context

---

Routes and actions together make published APIs first-class on Ouro: callable, billable, composable, and traceable end to end.
