# JavaScript

Call your saved API from a Node.js server or worker using the built-in `fetch`. This guide makes one bounded request, saves its response, and checks the execution summary before accepting records.

## Before you start

Use Node.js 20 or later and a validated collection API with `max_pages` and `detail_limit` inputs. For a search API or a different input schema, adapt the body to the request supplied by your workspace. You do not need a CleanedWeb SDK.

Keep the API key on the server. A browser application should call your own backend; do not bundle the key into browser code or expose it through public environment variables.

## Configure the request

Load these variables through your server's secret and configuration management:

| Variable | Value |
| --- | --- |
| `CLEANEDWEB_API_BASE` | The HTTPS API origin supplied by the workspace. |
| `CLEANEDWEB_SOURCE_ID` | Your saved source identifier. |
| `CLEANEDWEB_DEFINITION_VERSION` | The reviewed, lowercase 64-character definition version. |
| `CLEANEDWEB_API_KEY` | A credential with access to this source and the `run` scope. |
| `CLEANEDWEB_IDEMPOTENCY_KEY` | A saved identifier for this one intended execution. |

Generate and persist the idempotency key with your request before sending. Keep the same key and body while investigating an uncertain outcome. Assign a new key for a new intentional collection. See [idempotency and recovery](/docs/idempotency/).

The example sends this body with your saved version substituted for the placeholder:

```json
{
  "expected_version": "YOUR_SAVED_DEFINITION_VERSION",
  "input": {
    "max_pages": 1,
    "detail_limit": 0
  }
}
```

These limits collect at most one collection page without detail-page enrichment. They do not specify a universal number of records or establish complete coverage.

## Run the example

Download [website-api.mjs](/examples/website-api.mjs), review it, and run it after setting your configuration. Use a fresh private directory or a unique output filename for each intended run so a later invocation cannot overwrite earlier evidence.

```bash
umask 077
node website-api.mjs > response.json
```

The script sends one `POST /v1/sources/{source_id}/run` with bearer authentication, the saved idempotency key, and a 60-second client timeout. It rejects redirects and has no automatic retries. A timeout stops the client's wait; it does not establish that server execution stopped.

## Check the outcome

| Exit code | Meaning | Next action |
| --- | --- | --- |
| `0` | A `completed` or `bounded` response passed its scope and matched both returned definition versions. | Validate record fields against your schema before storage. |
| `2` | The result needs review: partial, failed scope, missing summary, or a version mismatch. | Preserve the result and investigate before downstream use. |
| `1` | Configuration, network, HTTP, or response error. | Inspect the saved request and workspace before another execution. |

Successful JSON responses are preserved in `response.json`, including their summary. HTTP failures save only the HTTP status; raw error bodies are excluded because they can echo credentials. Connection errors may leave an empty file, so never interpret an empty output file as an empty collection.

Keep `delivery.runId` and `traceId` when returned. Use the [run reference](/docs/run-api/) to retrieve a retained result with an appropriately scoped key. A passing bounded result can still have `catalog_complete: false`.

Continue with [storage and deduplication](/docs/storing-results/), [scheduled collection](/docs/scheduled-runs/), and the [production checklist](/docs/production-checklist/).
