> ## Documentation Index
> Fetch the complete documentation index at: https://docs.valendata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /v1/skills/run — Run a Published Skill Programmatically

> Execute a published Skill by ID or by slug and receive strict JSON output enforced against the Skill's defined output schema.

Calling `POST /v1/skills/run` is the primary way to execute a Skill programmatically. You supply the Skill's ID (or use the slug-based variant) along with any parameter values your automation needs, and Valendata spins up a real Chromium session, runs the task, and returns structured JSON output in a single synchronous response.

## Endpoints

Two variants are available. Pick whichever matches how you identify the Skill:

```text theme={null}
POST https://api.valendata.com/v1/skills/run
POST https://api.valendata.com/v1/skills/{slug}/run
```

* The ID-based endpoint takes `skill_id` in the request body.
* The slug-based endpoint takes the Skill's `slug` in the URL path.

## Authentication

Pass your API key in the `Authorization` header as a Bearer token. Create and manage API keys from **Settings → API Keys** inside [app.valendata.com](https://app.valendata.com).

```http theme={null}
Authorization: Bearer vd_sk_YOUR_API_KEY
```

<Warning>
  Keep your API key secret. Do not expose it in client-side code, public repositories, or log output. Rotate a compromised key immediately from the dashboard.
</Warning>

## Request Body

<ParamField body="skill_id" type="string" required>
  The unique identifier of the published Skill to execute. Skill IDs follow the format `skl_...`. Find a Skill's ID on its detail page in the dashboard or via [`GET /api/skills`](/api-reference/skills/list).

  Required for `POST /v1/skills/run`. Omit when using the slug-based endpoint.
</ParamField>

<ParamField body="parameters" type="object">
  A key-value map of parameter values to pass to the Skill. Parameter names must match those defined in the Skill's configuration. Omit this field entirely if the Skill takes no parameters.

  ```json theme={null}
  { "page": "/bestsellers", "max_results": 50 }
  ```
</ParamField>

## Example Request

<Tabs>
  <Tab title="cURL (by ID)">
    ```bash theme={null}
    curl -X POST https://api.valendata.com/v1/skills/run \
      -H "Authorization: Bearer vd_sk_YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "skill_id": "skl_b281b8165a23",
        "parameters": { "page": "/bestsellers" }
      }'
    ```
  </Tab>

  <Tab title="cURL (by slug)">
    ```bash theme={null}
    curl -X POST https://api.valendata.com/v1/skills/bestsellers-scraper/run \
      -H "Authorization: Bearer vd_sk_YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "page": "/bestsellers" }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.post(
        "https://api.valendata.com/v1/skills/run",
        headers={
            "Authorization": "Bearer vd_sk_YOUR_API_KEY",
            "Content-Type": "application/json",
        },
        json={
            "skill_id": "skl_b281b8165a23",
            "parameters": {"page": "/bestsellers"},
        },
    )

    data = response.json()
    print(data["data"])
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    const response = await fetch("https://api.valendata.com/v1/skills/run", {
      method: "POST",
      headers: {
        "Authorization": "Bearer vd_sk_YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        skill_id: "skl_b281b8165a23",
        parameters: { page: "/bestsellers" },
      }),
    });

    const result = await response.json();
    console.log(result.data);
    ```
  </Tab>
</Tabs>

## Response

A successful run returns HTTP `200` with the following fields.

<ResponseField name="status" type="string">
  The terminal state of the run. Either `"completed"` when the Skill finishes successfully, or `"failed"` when the Skill encounters an unrecoverable error (see `error` for details).
</ResponseField>

<ResponseField name="data" type="array">
  Structured JSON output produced by the Skill, validated against the Skill's defined output schema. Each element is an object whose shape matches the schema you configured when building the Skill. This field is `null` when `status` is `"failed"`.
</ResponseField>

<ResponseField name="count" type="integer">
  The number of items in `data`.
</ResponseField>

<ResponseField name="execution_time_ms" type="integer">
  Total wall-clock execution time for the run, in milliseconds.
</ResponseField>

<ResponseField name="error" type="string | null">
  Error message if the run failed, otherwise `null`.
</ResponseField>

### Example Response

```json theme={null}
{
  "status": "completed",
  "data": [
    { "name": "Widget Pro", "price": 129.00, "in_stock": true },
    { "name": "Widget Lite", "price": 49.00, "in_stock": false }
  ],
  "count": 2,
  "execution_time_ms": 18400,
  "error": null
}
```

## Error Handling

| HTTP Status | Meaning                                                                                                                                               |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`       | Bad request, missing required field or invalid parameter value.                                                                                       |
| `401`       | Unauthorized, API key is missing, malformed, or revoked.                                                                                              |
| `404`       | Skill not found, the provided `skill_id` or slug does not exist in the current Workspace.                                                             |
| `429`       | Rate limited or insufficient credits, you have exceeded the request rate for your plan or your Workspace credit balance is too low to start this run. |
| `500`       | Internal error, something went wrong on Valendata's infrastructure. Check [status.valendata.com](https://status.valendata.com).                       |

<Note>
  Error responses use a `detail` field, for example: `{ "detail": "Your workspace has 3 credits remaining; this run requires at least 5." }`
</Note>

## Credit Usage

Each run deducts credits based on three components:

<CardGroup cols={3}>
  <Card title="LLM Tokens" icon="brain">
    Every reasoning step the AI agent takes consumes tokens. More complex pages and longer task descriptions use more tokens.
  </Card>

  <Card title="Browser Session Time" icon="clock">
    Credits accrue for every minute of active Chromium session. Faster-loading pages and tighter task scopes keep costs lower.
  </Card>

  <Card title="Web Searches" icon="magnifying-glass">
    If your Skill requires the agent to perform a web search as part of its task, each search costs a small number of credits.
  </Card>
</CardGroup>

<Tip>
  To predict run costs before scaling, run a Skill manually from the dashboard once and check the **Run Details** panel for a credit breakdown. Credits never expire, so topping up your balance in advance carries no risk.
</Tip>
