`POST /execute` is the stable REST entry point for every registered capability. The web layer never special-cases a platform ID; the capability's registered manifest supplies its input schema, timeout, example, canary, and fixed credit cost.

## Request

```http
POST https://data.upscrape.com/execute
Authorization: Bearer UPSCRAPE_API_KEY
Content-Type: application/json
Prefer: wait=30
Idempotency-Key: UNIQUE_LOGICAL_OPERATION
```

```json
{
  "capability": "platform.capability.action",
  "input": {}
}
```

`capability` must be an available capability ID. `input` must satisfy that capability's JSON Schema. Find both on its [public platform page](/scrapers).

## Waiting for completion

Without `Prefer: wait`, execution is asynchronous and normally returns HTTP `202`. Send `Prefer: wait=N` to wait for up to `N` seconds, with a server-side maximum of 300 seconds.

A wait is a response preference, not a different job type. If the job is still running when the window ends, Upscrape returns the same job as pending.

## Completed response

Completed work returns HTTP `200` with `state: "completed"` and `success: true`. Capability output is intentionally open-ended because each upstream source has a different data shape.

```json
{
  "job_id": "job_id",
  "state": "completed",
  "success": true,
  "results": [
    {"data": {"...": "capability-specific JSON"}}
  ],
  "billing": {"credits_charged": 1},
  "stats": {}
}
```

Use the capability's sample response as a realistic preview, but treat its input schema, not the sample output, as the validation contract.

## Pending response

Pending work returns HTTP `202` with a job ID and non-terminal `state`. Poll the job instead of resubmitting the execution.

## Validation

Invalid capability IDs, malformed JSON, and schema-invalid inputs fail before worker execution. Fix the request rather than retrying it unchanged.

When a waited job fails, the response keeps `state: "failed"` and uses a non-2xx status. Known validation, authorization, upstream, and availability failures map to their documented HTTP class; an unrecognized terminal failure is HTTP `500`, never a successful `200`.

## Charging

The fixed capability cost is charged once when the logical job completes successfully. Polls, internal retries, failed executions, and idempotent replays do not add another capability charge.
