> This page is optimized for agents. Use the linked Markdown pages and llms.txt indexes for related API content.

# Create a hosted, block-addressed working document.

> Create a hosted, block-addressed working document. Substrate serves it at /doc/<id> behind a signed expiring link; humans read and edit it in a browser (phone included) while agents patch it by block, and every change emits a substrate event so git-sync / Telegram / UAT pipelines pick it up. Create the SKELETON FIRST — title plus one `pending` block per section — then fill each with workspace.doc.patch, so the reader watches it fill and a second agent can claim a different section.

- Product: Workspace
- Section: workspace
- Snapshot: v0.1.0+8bf142be
- Method: `POST`
- Path: `/v1/abilities/workspace.doc.create`

## Request body

Required: yes  
Content types: `application/json`  

### `input`

Type: `WorkspaceDocCreateInput`  
Required: yes  

#### `title`

Type: `string`  
Required: yes  

document title, shown in the header

#### `product`

Type: `string`  
Required: no  

recipe name, e.g. sebenza — scopes listing

#### `kind`

Type: `string`  
Required: no  
Allowed values: `plan`, `handoff`, `research`, `report`, `brief`, `uat`, `note`  
Default: `note`  

#### `owner`

Type: `string`  
Required: no  

who the document is FOR (the human), shown in the header

#### `edit_event`

Type: `string`  
Required: no  
Default: `workspace.doc.edited`  

substrate event emitted on every change

#### `blocks`

Type: `object[]`  
Required: yes  

##### object

Type: `object`  

One addressable section. `pending` = a placeholder with a written intent (create the skeleton FIRST, then fill each one — the human watches it fill and a second agent can claim a different section). `markdown` = prose. `ui` = a UIPrimitive from the ui__render vocabulary, validated against the same per-key component scope as a chat render. `decision` = a question with options a human taps. `checks` = QA-style checks a tester runs.

###### `type`

Type: `string`  
Required: yes  
Allowed values: `pending`, `markdown`, `ui`, `decision`, `checks`  

###### `id`

Type: `string`  
Required: no  

stable address, e.g. "goals" — auto-assigned (b1, b2…) if omitted. Patches target this.

###### `intent`

Type: `string`  
Required: no  

pending: what this section will contain. A contract the filling agent is held to.

###### `content`

Type: `string`  
Required: no  

markdown: the body

###### `node`

Type: `object`  
Required: no  

ui: a UIPrimitive (chart / datagrid / stat / table / grid / card / list / text)

###### `question`

Type: `string`  
Required: no  

decision: what is being decided

###### `options`

Type: `array`  
Required: no  

decision: 2-8 options, string or {label,value,description}

###### `chosen`

Type: `string`  
Required: no  

decision: the selected value

###### `tests`

Type: `array`  
Required: no  

checks: [{title, steps[], expected_good, expected_bad, where}]

### `context`

Type: `CallContext`  
Required: no  

Optional call context. The tenant always comes from the credential: `tenantId` is honoured only by a credential allowed to address sub-tenants, and then nests under the credential's own tenant.

#### `tenantId`

Type: `string`  
Required: no  

Sub-tenant to act for (sub-tenant credentials only).

#### `runId`

Type: `string`  
Required: no  

The trust run (from trust.preflight) this call executes under.

#### `verticalId`

Type: `string`  
Required: no  

Vertical to attribute created records to.

## Execute with curl

```bash
curl -X POST https://substrate.sloelabs.com/v1/abilities/workspace.doc.create \
    -H "Authorization: Bearer $SLOE_API_KEY" \
    -H 'Content-Type: application/json' \
    -d '{"input":{"title":"<title>","blocks":[{"type":"pending"}]}}'
```

## Execute with JavaScript

```js
const response = await fetch("https://substrate.sloelabs.com/v1/abilities/workspace.doc.create", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SLOE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "input": {
      "title": "<title>",
      "blocks": [
        {
          "type": "pending"
        }
      ]
    }
  }),
});
const { ok, result, error } = await response.json();
```

## Execute with Python

```python
import os
import requests

response = requests.post(
    "https://substrate.sloelabs.com/v1/abilities/workspace.doc.create",
    headers={"Authorization": f"Bearer {os.environ['SLOE_API_KEY']}"},
    json={
        "input": {
            "title": "<title>",
            "blocks": [{
                "type": "pending",
            }],
        },
    },
)
print(response.json())
```

## Responses

### Response `200`

Category: success  

The ability ran.

#### `application/json`

Documentation payload key: `result`  

##### Generated example

```json
{
  "ok": true,
  "ability": "ability",
  "duration": 0
}
```

##### Schema

###### AbilityResult

Type: `AbilityResult`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `ability`

Type: `string`  
Required: yes  

The ability that ran.

###### `result`

Type: `unknown`  
Required: yes  

The ability's return value. Its shape depends on the ability.

###### `duration`

Type: `number`  
Required: yes  

Server-side execution time, in milliseconds.

### Response `400`

Category: client-error  

The body is missing `input`, or `input` fails the ability's schema (`details` holds the validation errors).

#### `application/json`

##### Generated example

```json
{
  "ok": true,
  "error": "error",
  "ability": "ability",
  "reason": "reason",
  "details": [
    {}
  ],
  "retryAfterMs": 0
}
```

##### Schema

###### ErrorResponse

Type: `ErrorResponse`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `error`

Type: `string`  
Required: yes  

###### `ability`

Type: `string`  
Required: no  

###### `reason`

Type: `string`  
Required: no  

###### `details`

Type: `object[]`  
Required: no  

JSON Schema validation errors.

###### object

Type: `object`  

###### `code`

Type: `unknown`  
Required: no  

A machine-readable error code, when the ability sets one.

###### `retryAfterMs`

Type: `number`  
Required: no  

### Response `401`

Category: client-error  

No bearer credential, or one the substrate does not recognise.

#### `application/json`

##### Generated example

```json
{
  "ok": true,
  "error": "error",
  "ability": "ability",
  "reason": "reason",
  "details": [
    {}
  ],
  "retryAfterMs": 0
}
```

##### Schema

###### ErrorResponse

Type: `ErrorResponse`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `error`

Type: `string`  
Required: yes  

###### `ability`

Type: `string`  
Required: no  

###### `reason`

Type: `string`  
Required: no  

###### `details`

Type: `object[]`  
Required: no  

JSON Schema validation errors.

###### object

Type: `object`  

###### `code`

Type: `unknown`  
Required: no  

A machine-readable error code, when the ability sets one.

###### `retryAfterMs`

Type: `number`  
Required: no  

### Response `403`

Category: client-error  

The credential is valid, but its scope does not include this ability.

#### `application/json`

##### Generated example

```json
{
  "ok": true,
  "error": "error",
  "ability": "ability",
  "reason": "reason",
  "details": [
    {}
  ],
  "retryAfterMs": 0
}
```

##### Schema

###### ErrorResponse

Type: `ErrorResponse`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `error`

Type: `string`  
Required: yes  

###### `ability`

Type: `string`  
Required: no  

###### `reason`

Type: `string`  
Required: no  

###### `details`

Type: `object[]`  
Required: no  

JSON Schema validation errors.

###### object

Type: `object`  

###### `code`

Type: `unknown`  
Required: no  

A machine-readable error code, when the ability sets one.

###### `retryAfterMs`

Type: `number`  
Required: no  

### Response `404`

Category: client-error  

No ability has this id.

#### `application/json`

##### Generated example

```json
{
  "ok": true,
  "error": "error",
  "ability": "ability",
  "reason": "reason",
  "details": [
    {}
  ],
  "retryAfterMs": 0
}
```

##### Schema

###### ErrorResponse

Type: `ErrorResponse`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `error`

Type: `string`  
Required: yes  

###### `ability`

Type: `string`  
Required: no  

###### `reason`

Type: `string`  
Required: no  

###### `details`

Type: `object[]`  
Required: no  

JSON Schema validation errors.

###### object

Type: `object`  

###### `code`

Type: `unknown`  
Required: no  

A machine-readable error code, when the ability sets one.

###### `retryAfterMs`

Type: `number`  
Required: no  

### Response `429`

Category: client-error  

Too many requests for this credential. `retryAfterMs` says when to retry.

#### `application/json`

##### Generated example

```json
{
  "ok": true,
  "error": "error",
  "ability": "ability",
  "reason": "reason",
  "details": [
    {}
  ],
  "retryAfterMs": 0
}
```

##### Schema

###### ErrorResponse

Type: `ErrorResponse`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `error`

Type: `string`  
Required: yes  

###### `ability`

Type: `string`  
Required: no  

###### `reason`

Type: `string`  
Required: no  

###### `details`

Type: `object[]`  
Required: no  

JSON Schema validation errors.

###### object

Type: `object`  

###### `code`

Type: `unknown`  
Required: no  

A machine-readable error code, when the ability sets one.

###### `retryAfterMs`

Type: `number`  
Required: no  

### Response `501`

Category: server-error  

The ability is declared but no handler is wired.

#### `application/json`

##### Generated example

```json
{
  "ok": true,
  "error": "error",
  "ability": "ability",
  "reason": "reason",
  "details": [
    {}
  ],
  "retryAfterMs": 0
}
```

##### Schema

###### ErrorResponse

Type: `ErrorResponse`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `error`

Type: `string`  
Required: yes  

###### `ability`

Type: `string`  
Required: no  

###### `reason`

Type: `string`  
Required: no  

###### `details`

Type: `object[]`  
Required: no  

JSON Schema validation errors.

###### object

Type: `object`  

###### `code`

Type: `unknown`  
Required: no  

A machine-readable error code, when the ability sets one.

###### `retryAfterMs`

Type: `number`  
Required: no  

### Response `default`

Category: default  

The ability failed. The message is sanitized; a 5xx may be a transient upstream failure.

#### `application/json`

##### Generated example

```json
{
  "ok": true,
  "error": "error",
  "ability": "ability",
  "reason": "reason",
  "details": [
    {}
  ],
  "retryAfterMs": 0
}
```

##### Schema

###### ErrorResponse

Type: `ErrorResponse`  

###### `ok`

Type: `boolean`  
Required: yes  

###### `error`

Type: `string`  
Required: yes  

###### `ability`

Type: `string`  
Required: no  

###### `reason`

Type: `string`  
Required: no  

###### `details`

Type: `object[]`  
Required: no  

JSON Schema validation errors.

###### object

Type: `object`  

###### `code`

Type: `unknown`  
Required: no  

A machine-readable error code, when the ability sets one.

###### `retryAfterMs`

Type: `number`  
Required: no  

## Related representations

- [Human documentation](/api/workspace/doc/methods/create/)
- [curl Markdown](/api/workspace/doc/methods/create.md?lang=curl)
- [JavaScript Markdown](/api/workspace/doc/methods/create.md?lang=fetch)
- [Python Markdown](/api/workspace/doc/methods/create.md?lang=python)
- [site llms.txt](/api/llms.txt)
- [product llms.txt](/api/workspace/llms.txt)
- [snapshot llms.txt](/api/workspace/llms.txt)
