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

# POST /v1/blocks/objective

> Create a objective block with its content as plain text.

What the assistant has to achieve in the conversation, and how you know it did. Keeps an assistant from being helpful in general and useless in particular.

The block is created in the project catalogue and is **not attached to anything**. Wire it into an assistant with [`POST /v1/assistants/{id}/blocks`](/dev/endpoints/assistants-block-attach) afterwards.

<Note>
  **Identity block: one per assistant.** A second `objective` on the same assistant fails with `ASSISTANT_DUPLICATE_IDENTITY_BLOCK`.
</Note>

## Endpoint

```
POST https://api.keebai.com/v1/blocks/objective
```

## Required scope

`assistants:write`

## Headers

| Header          | Required | Value                    |
| --------------- | -------- | ------------------------ |
| `Authorization` | Yes      | `Bearer kbai_pk_<token>` |
| `Content-Type`  | Yes      | `application/json`       |

## Body

| Field     | Type     | Required | Description                                                                   |
| --------- | -------- | -------- | ----------------------------------------------------------------------------- |
| `name`    | `string` | Yes      | Up to 150 characters. What the block shows as in the portal.                  |
| `content` | `string` | No       | The block's text, up to 100,000 characters. Omit it to create an empty block. |

`type` and `family` are not accepted: the type is the endpoint you called, and `family` is derived from it (`identity` for this one).

## Example request

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.keebai.com/v1/blocks/objective \
    -H "Authorization: Bearer kbai_pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Objetivo",
      "content": "# Objetivo\nCerrar una reserva en el primer intercambio de mensajes.\n\n## Se logró cuando\n- El cliente eligió servicio, día y hora.\n- Quedó registrada la reserva."
    }'
  ```

  ```js JavaScript theme={null}
  const resp = await fetch("https://api.keebai.com/v1/blocks/objective", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.KEEBAI_API_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Objetivo",
      content: "# Objetivo\nCerrar una reserva en el primer intercambio de mensajes.\n\n## Se logró cuando\n- El cliente eligió servicio, día y hora.\n- Quedó registrada la reserva.",
    }),
  });

  const { block } = await resp.json();

  // Then wire it into an assistant.
  await fetch("https://api.keebai.com/v1/assistants/6650a1b2c3d4e5f6a7b8c9d0/blocks", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.KEEBAI_API_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ block_id: block._id }),
  });
  ```

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

  resp = requests.post(
      "https://api.keebai.com/v1/blocks/objective",
      headers={"Authorization": f"Bearer {os.environ['KEEBAI_API_TOKEN']}"},
      json={"name": "Objetivo", "content": "# Objetivo\nCerrar una reserva en el primer intercambio."},
      timeout=10,
  )
  resp.raise_for_status()
  block = resp.json()["block"]
  ```
</CodeGroup>

## Response

### 201 Created

```json theme={null}
{
  "block": {
    "_id": "6650bbbb2222cccc3333dddd",
    "type": "objective",
    "family": "identity",
    "name": "Objetivo",
    "current_version_id": "6650ffff4444aaaa5555bbbb",
    "is_archived": false,
    "content_writable": true,
    "created_at": "2026-07-26T21:38:22.104Z",
    "updated_at": "2026-07-26T21:38:22.104Z"
  }
}
```

### 400 Bad Request

Missing `name`, `content` over 100,000 characters, or a property the endpoint does not accept.

### 401 Unauthorized

Missing, invalid, revoked, or expired token.

### 403 Forbidden

The token does not have the `assistants:write` scope.

### 502 Bad Gateway

The assistant service is unreachable.

## Operational notes

* An objective works best when it names a single outcome. Two competing objectives in one block tend to produce an assistant that pursues neither.
* **Creating a block also creates its first version.** The response already carries a `current_version_id`, even when you omit `content` — the block starts with one empty version rather than none.
* **Creation is not idempotent.** Nothing enforces unique names, so a retry after a timeout leaves you with two blocks. Check [the catalogue](/dev/endpoints/blocks-list) filtered by `type` before retrying.
* **Content is plain text with three markdown conventions**: `-` for bullets, `1.` for numbered items, `#` for headings. Everything else is a paragraph. [More on how content is stored](/dev/assistants/overview#content-is-text).
* **The block belongs to the token's project**, and a token on another project can neither see it nor read it by id.


## OpenAPI

````yaml POST /v1/blocks/objective
openapi: 3.0.0
info:
  title: Keebai Public API
  description: Superficie pública REST autenticada con Personal Access Tokens (PAT).
  version: 1.0.0
  contact: {}
servers:
  - url: https://api.keebai.com
    description: Production
security: []
tags: []
paths:
  /v1/blocks/objective:
    post:
      tags:
        - blocks
      summary: Crear un bloque de objetivo
      description: >-
        Que tiene que lograr el asistente en la conversacion y como se sabe que
        lo logro. Bloque de identidad, uno por asistente.
      operationId: PublicBlocksController_createObjective
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicBlockCreateDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicBlockEnvelopeDto'
      security:
        - PAT: []
components:
  schemas:
    PublicBlockCreateDto:
      type: object
      properties:
        name:
          type: string
          maxLength: 150
          description: Nombre con el que el bloque aparece en el portal.
          example: Tono cercano
        content:
          type: string
          maxLength: 100000
          description: >-
            Contenido inicial en texto. Se reconocen listas con '-' y con '1.',
            y encabezados con '#'. Sin este campo el bloque nace vacio.
      required:
        - name
    PublicBlockEnvelopeDto:
      type: object
      properties:
        block:
          $ref: '#/components/schemas/PublicBlockDto'
      required:
        - block
    PublicBlockDto:
      type: object
      properties:
        _id:
          type: string
        type:
          type: string
          enum:
            - personification
            - objective
            - response_format
            - steps
            - cases_possible
            - do_not
            - product_info
            - store_info
            - reservation_info
            - tables_info
            - tags
            - response_policy
        family:
          type: string
          enum:
            - identity
            - instructions
            - information
          description: >-
            Se deriva del tipo y determina en que seccion del prompt entra el
            bloque. Es de solo lectura.
        name:
          type: string
        current_version_id:
          type: string
          nullable: true
          description: >-
            Version vigente del bloque. Su contenido se lee en GET
            /v1/blocks/{id}/content.
        is_archived:
          type: boolean
        content_writable:
          type: boolean
          description: >-
            Si el contenido de este bloque se puede editar por API. Los tipos de
            catalogo son de solo lectura porque su escritura depende de una
            sincronizacion de funciones que vive en el portal.
        created_at:
          type: string
        updated_at:
          type: string
      required:
        - _id
        - type
        - family
        - name
        - current_version_id
        - is_archived
        - content_writable
        - created_at
        - updated_at
  securitySchemes:
    PAT:
      scheme: bearer
      bearerFormat: kbai_pk_<hex>
      type: http
      description: >-
        Personal Access Token con prefijo `kbai_pk_`. Generar desde el portal
        con permiso `developer.manage_tokens`.

````