> ## 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.

# Create a skill

> Make a skill from one sentence, by recording yourself in the app, or by cloning one from the marketplace.

There are three ways to get a skill:

| Way | Best for | Can sign in to sites? |
| - | - | - |
| [From a sentence](#from-a-sentence) | Public pages: search results, listings, directories. | No |
| [By recording it](#by-recording-it) | Tasks behind your sign-in, or that need exact clicks. | Yes |
| [From the marketplace](/guides/use-the-marketplace) | Common tasks someone has already built. | Depends on the skill |

## From a sentence

You describe the task and the page it starts on. Valendata does the task in a cloud browser, learns the steps, and checks them with one more run. This takes a few minutes.

You can start it from:

* **The app**: **My Skills → Create Skill → Describe it**. The product tour and Igris, the in-app assistant, can do it too.
* **Your AI assistant**: ask it to create a skill. It uses the `create_skill` tool. See [MCP tools](/ai-assistants/mcp-tools).
* **The API**: [`POST /v1/skills`](/api-reference/skills/create).

Optionally name the **inputs** (with the example value the task uses) and the **output fields** you want. If you leave them out, Valendata works them out from the task. Names are turned into `snake_case`, so `Phone number` becomes `phone_number`.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.valendata.com/v1/skills \
    -H "Authorization: Bearer $VALENDATA_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: dentists-austin-001" \
    -d '{
      "task": "Search for dentists in Austin and list them",
      "start_url": "https://www.google.com/maps",
      "inputs": {"city": "Austin"},
      "output_fields": {"name": "business name", "rating": "star rating", "phone": "phone number"}
    }'
  ```

  ```python Python theme={null}
  import os, time, requests

  API = "https://api.valendata.com"
  HEADERS = {"Authorization": f"Bearer {os.environ['VALENDATA_API_KEY']}"}

  creation = requests.post(
      f"{API}/v1/skills",
      headers={**HEADERS, "Idempotency-Key": "dentists-austin-001"},
      json={
          "task": "Search for dentists in Austin and list them",
          "start_url": "https://www.google.com/maps",
          "inputs": {"city": "Austin"},
          "output_fields": {"name": "business name", "rating": "star rating", "phone": "phone number"},
      },
  ).json()

  while creation["status"] not in ("ready", "needs_fix", "failed"):
      time.sleep(30)
      creation = requests.get(f"{API}{creation['status_url']}", headers=HEADERS).json()
      print(creation.get("progress"))

  print(creation["status"], creation.get("slug"), creation.get("next_step"))
  ```
</CodeGroup>

The call answers at once with a `creation_id`. Read [`GET /v1/skill-creations/{creation_id}`](/api-reference/skills/get-creation) about every 30 seconds. Stop when `status` is `ready`, `needs_fix`, or `failed`.

| `status` | Meaning |
| - | - |
| `queued` | Waiting to start. |
| `recording` | The cloud browser is doing the task. |
| `validating` | Saved as a skill (`slug` is set). Valendata runs it once more to check it. |
| `ready` | Passed the check. You can run it. |
| `needs_fix` | Saved as a **draft** skill (`slug` is set), but the check run did not pass. Fix it with [`POST /v1/skills/{slug}/improve`](/api-reference/improvements/improve) (MCP: `improve_skill`). Do not create it again. |
| `failed` | Did not work and nothing was saved. `error` says why and `diagnosis` suggests what to try. |

Each check also tells you:

| Field | What it is |
| - | - |
| `task`, `start_url`, `name` | What you asked for. |
| `progress` | The latest step in plain words, such as `Step 4: typing 'trouser' into the search box`. Show it to whoever is waiting. |
| `next_step` | One sentence that says what to do next. |
| `sample_rows` | Up to 3 rows from the recording, set for `needs_fix` and `ready`. `sample_row_count` is how many rows the recording got. |
| `credits_charged` | Credits used so far, to 0.01. |

A creation that needs a fix looks like this:

```json theme={null}
{
  "creation_id": "sc_3f9a1c2b7d4e5f60",
  "status": "needs_fix",
  "status_url": "/v1/skill-creations/sc_3f9a1c2b7d4e5f60",
  "task": "Search for dentists in Austin and list them",
  "start_url": "https://www.google.com/maps",
  "name": "Austin dentists",
  "slug": "austin-dentists",
  "progress": "Check run finished: 0 of 3 fields came back",
  "next_step": "The skill was saved as a draft but its check run came back empty. Fix it with POST /v1/skills/austin-dentists/improve; do not create it again.",
  "sample_rows": [
    {"name": "Lone Star Dental", "rating": "4.8", "phone": "(512) 555-0142"},
    {"name": "Barton Creek Smiles", "rating": "4.6", "phone": "(512) 555-0198"},
    {"name": "Austin Family Dentistry", "rating": "4.9", "phone": "(512) 555-0117"}
  ],
  "sample_row_count": 20,
  "credits_charged": 14.35,
  "error": null
}
```

To see all your creations, newest first, use [List skill creations](/api-reference/skills/list-creations). Pass `status=active` for the ones still going.

**Limits:** 2 creations in progress at once, at least 10 credits to start, and 30 minutes per creation. A cloud browser starting fresh cannot sign in, so record tasks that need your sign-in instead.

## By recording it

<Steps>
  <Step title="Start recording">
    Open a new session from the dashboard. In the chat box, switch on **Record Skill**. It shows **Recording...** while it is on.
  </Step>

  <Step title="Do the task">
    Type the task for the agent, or use the browser yourself: sign in, search, page through results, and reach the data you want. Every step is recorded.
  </Step>

  <Step title="Stop and publish">
    Stop the session. The recording is saved under **Configs**. Open it, click **Publish as skill**, give it a name and description, choose the visibility, and click **Publish Skill**.
  </Step>

  <Step title="Check the inputs and output fields">
    Open the skill. Click **Suggest** to detect inputs and output fields from the recording, then rename or adjust them.
  </Step>
</Steps>

If the site needs a sign-in on later runs, attach a browser profile or a saved login. See [Use a saved login](/guides/use-a-saved-login).

## Next

* [Run a skill](/guides/run-a-skill)
* [Improve a skill](/guides/improve-a-skill) if a field comes back empty.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.