# Build backend operations

Source: /docs/building/backend-operations.md

An app needs a backend when a user asks for a result or makes a change: look up an order, calculate a quote, save an approval, or create a work order. Implement that request as a Python **API** and call it from the interface.

Use an API for request/response work. Use a [transform](/docs/building/query-and-prepare-data) for longer background calculations that publish reusable tables. An API can read those prepared results instead of repeating the calculation on every request.

## Separate caller inputs from managed dependencies [#separate-caller-inputs-from-managed-dependencies]

Your coding agent declares both in Python:

```python
from vortexify import Input, vxfy_api


@vxfy_api("/normalize", inputs={"value": Input(str, default="Hello")})
def api(value: str) -> dict:
    text = value.strip()
    return {"value": text, "length": len(text)}
```

`Input` is a scalar the caller supplies: a string, integer, float, or boolean. Data, secrets, and database connections are different declarations that the backend resolves:

| Need | Declaration |
| --- | --- |
| Read a synced dataset | `Table("shop.orders")` |
| Read an uploaded dataset | `Table("_upload.orders")` |
| Read a prepared calculation | `TransformOutput("order_totals")` |
| Read database rows as a table | `DatabaseTable("operations.work_orders")` |
| Perform scoped operational SQL | `Database("operations", tables=["work_orders"], mode="read_write")` |
| Use a managed credential | `Secret("erp_token")` |

These references belong in the API's `inputs` mapping, under local argument names. The browser supplies caller inputs; it does not send database credentials or the contents of managed tables. Create required secrets through platform configuration or the [CLI](/docs/reference/cli/configuration).

For Pandas, tabular inputs arrive as DataFrames. DuckDB registers them as relations under their local input names and injects `conn`. A tabular declaration does not automatically filter to the requested customer or record; implement that filtering and the necessary checks in your function. For operational writes, use parameterized SQL against the scoped database connection.

## Prepare dependencies before invoking the API [#prepare-dependencies-before-invoking-the-api]

Check that required sync or transform outputs have been published, database migrations are applied, and secrets have values. Declaring references does not create or run upstream resources.

The resource name, Python function name, and decorator path can differ. The CLI and React SDK call the registered resource name, such as `normalize`.

Your coding agent saves the intended code and prepares its preview runtime:

```sh
vortexify commit --type api --resource normalize
vortexify build api normalize --wait
vortexify test api normalize --wait
vortexify run api normalize --wait
```

A build prepares the runtime and dependencies. Mock tests check behavior using test inputs. A manual run invokes the saved API against live resolved dependencies. Use an inputs file for request values; see [CLI execution](/docs/reference/cli/execution) for syntax.

A preview invocation still performs writes implemented by the function. Waiting observes the existing request/job; a stopped wait does not undo it. Inspect its result before submitting the same write again.

## Give the interface a useful response [#give-the-interface-a-useful-response]

Return JSON-compatible values with a stable shape. Convert database rows, DataFrames, dates, decimals, and missing numeric values explicitly. APIs return a response; they do not publish transform output tables.

Keep validation required for every request inside the function. Optional SDK response validation is a separate diagnostic step and is skipped for deployed API calls. Tests should cover meaningful behavior, such as invalid inputs or a missing record, using mocks for external side effects.

In the platform, open the API **Playground**. **Configure** prepares the runtime or runs tests, **Run** accepts scalar inputs as a JSON object, and **History** lists executions. Select a run to inspect **Output**, **Processing**, **Logs**, or the full **JSON** result. **Code** can show working source or a read-only saved version. Compare that run's response to what the interface expects before wiring up the screen.

> **Platform screenshot placeholder:** An API execution with its saved version, scalar request inputs, response, and a link to execution logs.

Next: [Build your interface](/docs/building/build-your-interface). See [API contracts](/docs/reference/python/apis), [database configuration](/docs/building/store-app-data), and [testing and validation](/docs/reference/python/testing-and-validation) for details.
