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

# Quickstart

> Build, publish and run a two-company comparison end to end with curl.

# Quickstart

This builds a workflow that compares two companies and packs the result, then runs it. Every call uses the same base URL and bearer key.

```bash theme={null}
export BRIEFED_KEY="brf_live_..."
export BRIEFED_API="https://research-api.briefedmedia.com"
```

You need a key with `write:workflows` to publish and run. See [Authentication](/api-reference/workflows/authentication).

## 1. See what you can compose with

```bash theme={null}
curl "$BRIEFED_API/api/v1/workflows/catalogue/parts" \
  -H "Authorization: Bearer $BRIEFED_KEY"
```

Each part declares `requires` and `produces`. An edge is legal only when the upstream `produces` satisfies the downstream `requires`. Pass `?unattendedSafe=1` to see only the parts allowed on a scheduled trigger.

## 2. Pin the companies

Terminal parts run against canonical subjects, not names. Resolve the companies you want **in one call**. A step that compares needs at least two subjects, and resolving them one at a time cannot satisfy that.

```bash theme={null}
curl -X POST "$BRIEFED_API/api/v1/workflows/catalogue/resolve-subjects" \
  -H "Authorization: Bearer $BRIEFED_KEY" \
  -H "Content-Type: application/json" \
  -d '{"hints":["AAPL","MSFT"]}'
```

```json theme={null}
{
  "subjects": [
    { "canonicalId": "company:...", "kind": "company", "label": "Apple Inc.", "identifiers": [...] },
    { "canonicalId": "company:...", "kind": "company", "label": "Microsoft Corporation", "identifiers": [...] }
  ],
  "unresolved": []
}
```

Anything that could not be pinned comes back in `unresolved` with a reason and, where the fabric offered candidates, the choices:

```json theme={null}
{
  "unresolved": [
    {
      "hint": "Alphabet",
      "reason": "ambiguous",
      "candidates": [
        { "canonicalId": "...", "label": "Alphabet Inc. Class A", "ticker": "GOOGL" },
        { "canonicalId": "...", "label": "Alphabet Inc. Class C", "ticker": "GOOG" }
      ]
    }
  ]
}
```

Re-resolve with the ticker you meant. Reasons are `ambiguous`, `unlisted` (held, but with no listed equity to run against) and `lookup_failed` (the resolver could not be reached, which asserts nothing about the company).

## 3. Create the workflow

```bash theme={null}
curl -X POST "$BRIEFED_API/api/v1/workflows" \
  -H "Authorization: Bearer $BRIEFED_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Apple vs Microsoft"}'
```

Returns `201` with `{ "workflow": { "id": "..." } }`. Keep the id as `WF`.

## 4. Validate the graph before you save it

Validation runs the same rules the save route runs, so a graph that passes here will save.

```bash theme={null}
curl -X POST "$BRIEFED_API/api/v1/workflows/catalogue/validate-definition" \
  -H "Authorization: Bearer $BRIEFED_KEY" \
  -H "Content-Type: application/json" \
  -d @definition.json
```

With `definition.json`:

```json theme={null}
{
  "definition": {
    "schemaVersion": 1,
    "nodes": [
      { "id": "t1", "kind": "trigger", "trigger": { "kind": "on_demand" } },
      {
        "id": "compare",
        "partId": "terminal.comparative.research",
        "partVersion": "1",
        "terminal": {
          "job": { "id": "comparative.research", "version": "1" },
          "subjectRefs": [ /* the two subjects from step 2 */ ]
        }
      },
      { "id": "pack", "partId": "workflow.pack", "partVersion": "1" },
      { "id": "g1", "kind": "gate", "belowFloor": "hold" },
      { "id": "d1", "kind": "destination", "destination": { "kind": "standalone" } }
    ],
    "edges": [{ "from": "compare", "to": "pack" }]
  }
}
```

A valid graph returns its cost estimate:

```json theme={null}
{ "ok": true, "definition": {...}, "estimate": { "costMinorUnits": 450, "parts": [...] } }
```

An invalid one returns `400` with every fault at once, each naming the node it applies to. See [Errors](/api-reference/workflows/errors).

## 5. Save it as a version

```bash theme={null}
curl -X POST "$BRIEFED_API/api/v1/workflows/$WF/versions" \
  -H "Authorization: Bearer $BRIEFED_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scope":{"graph": { ... }}}'
```

The trigger, gate and destination may be carried as nodes in the graph, as above, or as top-level `trigger` and `destinations` fields. Returns the created version with its id.

## 6. Publish

A version is inert until published, and only a published version can run.

```bash theme={null}
curl -X POST "$BRIEFED_API/api/v1/workflows/$WF/versions/$VERSION/publish" \
  -H "Authorization: Bearer $BRIEFED_KEY"
```

## 7. Run

```bash theme={null}
curl -X POST "$BRIEFED_API/api/v1/workflows/$WF/run" \
  -H "Authorization: Bearer $BRIEFED_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
```

```json theme={null}
{ "ok": true, "runId": "...", "host": "workflow_run", "estimate": { "costMinorUnits": 450 } }
```

This reserves usage. **Always send `Idempotency-Key`**, because a retry without one starts a second run and spends again. See [Runs](/api-reference/workflows/runs).

## 8. Poll

```bash theme={null}
curl "$BRIEFED_API/api/v1/workflows/$WF/runs/$RUN_ID" \
  -H "Authorization: Bearer $BRIEFED_KEY"
```

The response carries the run's state and, for a composition, the child runs and their node outputs. Poll until the state is terminal.

## Templates

If you would rather start from something working, the curated gallery returns ready-made definitions you can copy and adapt:

```bash theme={null}
curl "$BRIEFED_API/api/v1/workflows/templates" -H "Authorization: Bearer $BRIEFED_KEY"
```
