# Call APIs and run transforms

Source: /docs/reference/react/calling-your-backend.md

Use an API when the user needs a result now, such as an order lookup or a saved decision. Use a transform when they start background work, such as recalculating a dataset. Both are selected by their registered project resource names.

## Call an API from an interaction [#call-an-api-from-an-interaction]

Inside a component under `VortexifyProvider`:

```tsx
import { useState } from "react";
import { useVortexify } from "@vortexify/react";

export function NormalizeForm() {
  const { client, ready } = useVortexify();
  const [value, setValue] = useState("");
  const [result, setResult] = useState<{ value: string; length: number } | null>(null);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function submit() {
    if (!ready || busy) return;
    setBusy(true); setError(null); setResult(null);
    try {
      setResult(await client.runApi<{ value: string; length: number }>("normalize", { value }));
    } catch (failure) {
      setError(failure instanceof Error ? failure.message : "Request failed");
    } finally { setBusy(false); }
  }

  return <form onSubmit={event => { event.preventDefault(); void submit(); }}>
    <label>Text <input value={value} onChange={event => setValue(event.target.value)} /></label>
    <button disabled={!ready || busy}>{busy ? "Processing…" : "Normalize"}</button>
    {error && <p role="alert">{error}</p>}
    {result && <p>{result.value} ({result.length} characters)</p>}
  </form>;
}
```

This assumes the `normalize` API from [backend operations](/docs/building/backend-operations) exists and its runtime is ready. `runApi` unwraps the execution envelope and returns the API's JSON value. The generic type describes what your component expects; the API still needs to return that shape.

Inputs are a mapping of strings, numbers, and booleans matching Python `Input` declarations. Managed tables, secrets, and database connections resolve on the backend. The client supplies project context and authentication; call `normalize`, not the Python function name or decorator route.

## Start and observe background work [#start-and-observe-background-work]

Starting a transform returns a job ID. Wait for that same job, inspect its terminal status, and then fetch the result your screen needs:

```ts
import type { VortexifyClient } from "@vortexify/react";

async function refreshOrders(client: VortexifyClient) {
  const { job_id } = await client.startTransform("refresh_orders", {});
  const job = await client.pollTransform("refresh_orders", job_id, {
    onProgress: snapshot => console.log(snapshot.status),
  });
  if (job.status !== "success") throw new Error(`Refresh ${job.status}`);
  return client.runApi("customer_orders", { customer_id: "123" });
}
```

Show progress and retain `job_id` in component/application state so a user can inspect existing work after a request fails. `getTransformJob(name, jobId)` reads a snapshot once; `pollTransform` repeats until terminal. Statuses `created`, `pending`, `queued`, and `running` are nonterminal; `success`, `failed`, and `stopped` are terminal.

Polling does not return published rows automatically. The example fetches them through an API after the run. In the platform, inspect the same run's **Output** and **Processing** views, and use its table publication to inspect schema and relationships when relevant.

## Preview and production [#preview-and-production]

The configured SDK mode applies to API and transform execution. Local development and hosted previews use committed preview resources. Published apps use production resources. Run required upstream producers and check their output before invoking consumers; see [configuration](/docs/reference/react/configuration#preview-lifecycle).

The current platform Playground submits committed preview runs. Starting a production transform from a published app uses the production execution path. A preview run does not activate production schedules.

## Errors, waiting, and retries [#errors-waiting-and-retries]

React SDK 0.1.1 preserves the server's JSON `message` on HTTP failures, with the HTTP status and decoded response available on `VortexifyError`. Non-JSON responses fall back to `HTTP <status>`. For example, “API runtime is not ready; build it through the CLI” means the server correctly rejected an unprepared runtime: run `vortexify build api NAME --wait` and inspect that build before invoking it again.

Methods accept `RequestOptions` with `signal` and `timeoutMs`. The request timeout defaults to the configured value or 60 seconds. `PollOptions` also accepts `intervalMs` (default 1,000) and `onProgress`; the total polling timeout defaults to five minutes.

A browser timeout, canceled request, or closed screen does not stop submitted backend work. Reuse the existing job ID when possible. An API may already have written data before its response is lost, so choose a deliberate retry/idempotency strategy for write operations.

See [API contracts](/docs/reference/python/apis), [transforms](/docs/reference/python/transforms), and [React configuration](/docs/reference/react/configuration).
