---
title: "Send Agent Playground Message"
method: POST
path: "/api/v1/agent-definitions/{definition_id}/playground/messages"
tags: ["authed"]
---

# Send Agent Playground Message

`POST /api/v1/agent-definitions/{definition_id}/playground/messages`

## Request

- Base URL: `https://api.teaflask.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.teaflask.com/api/v1/agent-definitions/{definition_id}/playground/messages`
- Auth: none declared

Testing drafts is authoring: the playground door creates-or-continues
the caller's own conversation pinned to this definition, whose turns
run the definition's latest revision — publish state never consulted —
and which never surfaces in the regular thread list. Same queue-and-
wake shape, unrunnable-config 409, and honest 503 as the assistant
messages endpoint (TEA-772: a message during a live turn queues —
the busy 409 has no producer left).

## Path parameters

- `definition_id` string, uuid, required

## Request body

- SendAssistantMessageRequest
  - `thread_id` string, uuid, nullable
  - `message` string
  - `attachment_ids` string[]

## Response `201`

Successful Response

- SendAssistantMessageResponse
  - `thread` AssistantThreadResponse, required
    - `id` string, uuid, required
    - `title` string, required
    - `busy` boolean, required
    - `stream_thread_id` string, required
    - `created_at` string, date-time, required
    - `updated_at` string, date-time, required
  - `turn` AssistantTurnResponse, required
    - `id` string, uuid, required
    - `thread_id` string, uuid, required
    - `user_message` string, required
    - `kind` 'delivery', required
    - `attachments` TurnAttachmentResponse[]
      - `id` string, uuid, required: The attachment's id.
      - `kind` 'image' | 'document' | 'video' | 'audio' | 'file', required: The assistant_attachments kind CHECK's closed set.
      - `format` string, nullable, required: The file's format, such as png or pdf; null when unknown.
      - `filename` string, required: The file's name as uploaded.
      - `byte_size` integer, required: The file's size in bytes.
    - `status` 'queued' | 'working' | 'awaiting_input' | 'succeeded' | 'failed' | 'parked' | 'superseded' | 'stopped', required
    - `error` string, nullable, required
    - `failure_reason` TurnFailureReason: Why the exchange failed: what kind of failure it was, and its facts.
      - `kind` 'no_backup_outage' | 'own_key_throttled' | 'own_key_outage' | 'own_key_declined' | 'own_key_required' | 'own_key_verifying' | 'backup_too_small' | 'summary_unavailable' | 'unfunded' | 'pocket_change_cap' | 'empty_balance' | 'model_contract_fault' | 'model_content_refused' | 'model_context_overflow' | 'model_provider_throttled' | 'subscription_unfunded' | 'subscription_unservable' | 'subscription_connect_required' | 'not_configured' | 'worker_lost' | 'runaway' | 'own_key_out_of_credit' | 'own_key_limited' | 'model_unlisted' | 'open_models_unavailable' | 'open_models_switched_off' | 'own_account_blocks_model', required: What kind of failure ended the exchange.
      - `detail` TurnFailureDetail: The facts behind the failure; each kind carries only its own.
        - `model_id` string, nullable: The model that was answering.
        - `provider` 'anthropic' | 'openai' | 'openrouter': Whose API a model call dials — the dimension BYOK keys, probes, bounce classification, and platform-key selection all key on. The vocabulary is append-only and each new value arrives with its integration (probe + classifier + key-shape rule + a platform key unless BYOK-only), never ahead of it.
        - `funding_source` 'balance' | 'byok' | 'end_user_subscription': Which pocket a model call bills against: the org's prepaid balance, the org's BYOK key, or an identified visitor's connected subscription. Per call, not per turn — one turn's rows may mix pockets. Closed partition under the llm_call_usage CHECK; the deduction paths drain the balance only for BALANCE rows. Complimentary money is BALANCE spend.
        - `which` 'message' | 'conversation', nullable: For a request too long for the model: whether the message alone or the whole conversation was too long.
        - `cause` 'tokens' | 'bytes' | 'summary_rejected', nullable: For a request too long for the model: what ran out.
        - `window_tokens` integer, nullable: How many tokens the model can read at once.
        - `plan_lapse` 'quota' | 'auth': Why a connected plan stopped paying: its usage limit, or its sign-in.
        - `balance_empty` boolean, nullable: For a declined API key: true when the balance was empty too, so neither could pay.
        - `welcome_credit_locked` boolean, nullable: For an empty balance: true when the organization had never added a card, so its welcome credit was still locked.
        - `redo_attempted` boolean, nullable: For an assistant that stopped unexpectedly: true when the step was already started again once on a fresh machine before it was given up.
        - `writer_prefix` string, nullable: For an assistant that stopped unexpectedly: the lost step's run and step ids, the prefix every write it made is labelled with — for support to find its trail.
        - `resets_at` string, date-time, nullable: When the key's spending limit resets.
    - `workflow_id` string, required
    - `run_id` string, nullable, required
    - `pending_interrupt_ids` string[]
    - `awaiting_round` integer, nullable
    - `pending_approvals` ApprovalRequestedMarker[]
      - `interrupt_id` string, required
      - `tool_name` string, nullable
      - `tool_args` object
      - `tool_input_schema` object, nullable
      - `tool_output_schema` object, nullable
      - `prompt` string, required
      - `tool_call_id` string, nullable
      - `round` integer
      - `gated` boolean
      - `trust_available` boolean
    - `pending_approval_displays` object
    - `unservable_interrupt_ids` string[]
    - `pending_coworker_executions` CoworkerExecutionRequestResponse[]
      - `ordinal` integer, required
      - `label` string, required
      - `child_session_id` string, required
      - `round` integer, required
      - `expires_at` string, date-time, required
      - `parked` boolean, required
      - `card` ToolExecutionRequestedMarker, required: The tool_execution_requested CUSTOM event's value payload. The tool_call_id anchors the card to the tool-call events already in the log; round is the loop round that paused, as on the approval card.
        - `interrupt_id` string, required
        - `tool_call_id` string, nullable
        - `tool_name` string, required
        - `round` integer
        - `request` ToolExecutionRequestPayload, required: The request half of a tool_execution_requested marker. kind is an open, additive vocabulary — clients ignore kinds they don't recognize. expires_at is advisory (the wait window that parks the turn rules).
          - `kind` string, required
          - `intent` object, nullable
          - `action` object, nullable
          - `expires_at` string, date-time, nullable
    - `pending_coworker_approvals` CoworkerApprovalRequestResponse[]
      - `ordinal` integer, required
      - `label` string, required
      - `child_session_id` string, required
      - `round` integer, required
      - `expires_at` string, date-time, required
      - `parked` boolean, required
      - `card` ApprovalRequestedMarker, required: The approval_requested CUSTOM event's value payload. The tool fields mirror the pending approval's best-effort shape (absent when no tool call was stopped); tool_input_schema / tool_output_schema are the paused tool's registered JSON schemas (a tool view reads the call without the catalog). round is the loop round that paused — what a fallback restart resumes one past. gated: the locked action-approval gate raised this pause; trust_available: the card may offer approve-and-stop-asking, scoped to the asker's own session (org hitl with trust enabled, never the gate).
        - `interrupt_id` string, required
        - `tool_name` string, nullable
        - `tool_args` object
        - `tool_input_schema` object, nullable
        - `tool_output_schema` object, nullable
        - `prompt` string, required
        - `tool_call_id` string, nullable
        - `round` integer
        - `gated` boolean
        - `trust_available` boolean
    - `agent_revision_id` string, uuid, nullable, required
    - `created_at` string, date-time, required
    - `updated_at` string, date-time, required

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `405`: Method not allowed
- `409`: The assistant's stored configuration cannot run, or the conversation's pending-message queue is at its cap
- `413`: The request body is over the 4 MiB message ceiling
- `422`: Validation error
- `500`: Internal server error
- `503`: Orchestration unavailable

## Changes

- **2026-11-03** `c6ac9fd6657f`: 9 info
  - removed the `STEEP_LEARNING_DISABLED` enum value from the `error/code` response property for the response status `401`
  - removed the `STEEP_LEARNING_DISABLED` enum value from the `error/code` response property for the response status `403`
  - removed the `STEEP_LEARNING_DISABLED` enum value from the `error/code` response property for the response status `404`
  - removed the `STEEP_LEARNING_DISABLED` enum value from the `error/code` response property for the response status `405`
  - …5 more

[Operation history](https://skmtc.dev/teaflask/apis/teaflask-api/changes/api/v1/agent-definitions/:definition_id/playground/messages/post.md)

---

[API](https://skmtc.dev/teaflask/apis/teaflask-api.md) - [All operations](https://skmtc.dev/teaflask/apis/teaflask-api/llms.txt) - [OpenAPI document](https://skmtc.dev/teaflask/apis/teaflask-api/revisions/c6ac9fd6657f?raw)
