## Quickstart

From zero to a running process instance in under five minutes.

### What you'll build

A trivial process called `hello-world` that takes one input and returns one output. You'll **register** it from YAML, **start** an instance via the API, and read the result back.

> **Prereq:** An OpenSOP engine reachable at `https://api.opensop.dev` and a workspace token. Set `export OPENSOP_TOKEN=sk_…` before running the snippets below.

### 1. Write the YAML

Save this as `hello-world.yaml`:

```yaml
opensop: "0.1"
process:
  name: hello-world
  version: "1.0"
  description: A trivial process
  inputs:
    - { name: who, type: string, required: true }
  outputs:
    - { name: greeting, type: string }
  steps:
    - id: greet
      type: automated
      run: ./greet.py
      outputs:
        - { name: greeting, value: "Hello, ${inputs.who}!" }
```

### 2. Register the process

Upload the YAML via multipart POST:

#### curl

```bash
curl https://api.opensop.dev/sop/processes/register \
  -X POST \
  -H "X-SOP-Token: $OPENSOP_TOKEN" \
  -F "file=@hello-world.yaml"
```

#### Node

```js
const form = new FormData();
form.append("file", fs.createReadStream("./hello-world.yaml"));
await fetch("https://api.opensop.dev/sop/processes/register", {
  method: "POST",
  headers: { "X-SOP-Token": process.env.OPENSOP_TOKEN },
  body: form
});
```

### 3. Start an instance

POST to start with inputs:

#### curl

```bash
curl https://api.opensop.dev/sop/hello-world/start \
  -X POST \
  -H "X-SOP-Token: $OPENSOP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"inputs":{"who":"world"}}'
```

#### Node

```js
const res = await fetch("https://api.opensop.dev/sop/hello-world/start", {
  method: "POST",
  headers: {
    "X-SOP-Token": process.env.OPENSOP_TOKEN,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ inputs: { who: "world" } })
});
const instance = await res.json();
```

### 4. Poll for completion

Read `state` from `GET /sop/hello-world/:id` until it is `completed` or `failed`.

#### curl

```bash
curl https://api.opensop.dev/sop/hello-world/:id \
  -H "X-SOP-Token: $OPENSOP_TOKEN"
```

#### Node

```js
// Poll until state is "completed" or "failed"
const check = async (id) => {
  const r = await fetch(
    `https://api.opensop.dev/sop/hello-world/${id}`,
    { headers: { "X-SOP-Token": process.env.OPENSOP_TOKEN } }
  );
  return r.json();
};
```

### Lifecycle

Instance states progress in this order:

`pending` → `running` → `waiting` → `running` → `completed`

On any error: `running` → `failed`

Cancelled instances move directly to `cancelled` from any non-terminal state.

### Next steps

- Add a `judgment` step with `allow_agent: true` to let an LLM decide.
- Add a `webhook` step to wait on a third party (Stripe, DocuSign, internal service).
- Replace polling with an outbound webhook on state_changed.

