API reference

Chat

Conversations, turns, streaming and interactions. The heart of the API.

List chats

GETapi.niucore.com/api/v1/chats

Scope: chat:read

Returns the chats belonging to this credential, newest first.

Per-credential namespace

A chat created from the application, or by another credential of the same user, does not show up here. In the application it is the other way round: the credential's chats are visible, readable and can be continued from the UI.

Query

is_favoriteboolean

Filters by favorite flag.

pageintegerdefaults to 1

Page number, starting at 1.

sizeintegerdefaults to 50

Items per page. Maximum 200.

Returns

idstring (uuid)

Chat identifier.

namestring | null

Conversation title.

is_favoriteboolean

Marked as favorite.

permission_modestring

manual or auto.

model_idinteger | null

Chat's default model.

created_atstring (date-time)

Created.

updated_atstring (date-time)

Last activity.

curl -sS -X GET 'https://api.niucore.com/api/v1/chats?page=1&size=20' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": [
    {
      "id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
      "name": "Soporte — ticket 8842",
      "is_favorite": false,
      "permission_mode": "auto",
      "model_id": 17,
      "created_at": "2026-09-01T14:02:11Z",
      "updated_at": "2026-09-01T14:09:44Z"
    }
  ],
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77",
    "page": 1,
    "size": 20,
    "total": 1
  }
}

Create a chat

POSTapi.niucore.com/api/v1/chats

Scope: chat:write

Creates an empty chat and returns its id.

Tip

It is not mandatory: sending a turn to a chat_id that does not exist creates it too. This endpoint exists for integrators that need the id before having the first message.

Request body

namestring

Title. 200 characters max.

model_idinteger

Default model. Valid ids come from GET /chat/catalog.

permission_modestringdefaults to manual

Chat default mode. Each turn can request its own.

manualauto

curl -sS -X POST 'https://api.niucore.com/api/v1/chats' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Soporte — ticket 8842",
    "permission_mode": "auto"
  }'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
    "name": "Soporte — ticket 8842",
    "is_favorite": false,
    "permission_mode": "auto",
    "model_id": 17,
    "created_at": "2026-09-01T14:02:11Z",
    "updated_at": "2026-09-01T14:09:44Z"
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Retrieve a chat

GETapi.niucore.com/api/v1/chats/{chat_id}

Scope: chat:read

Returns one of the credential's chats.

Path

chat_idstring (uuid)required

Chat identifier.

Errors

  • 404api_v1_not_foundThe chat does not exist or belongs to another credential. Both cases answer the same.
curl -sS -X GET 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
    "name": "Soporte — ticket 8842",
    "is_favorite": false,
    "permission_mode": "auto",
    "model_id": 17,
    "created_at": "2026-09-01T14:02:11Z",
    "updated_at": "2026-09-01T14:09:44Z"
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Rename or favorite

PATCHapi.niucore.com/api/v1/chats/{chat_id}

Scope: chat:write

Updates the name and the favorite flag. The model and the permission mode are not editable here: they travel per turn.

Path

chat_idstring (uuid)required

Chat identifier.

Request body

namestring

New title.

is_favoriteboolean

Sets or clears the favorite flag.

curl -sS -X PATCH 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Soporte — ticket 8842 (resuelto)",
    "is_favorite": true
  }'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
    "name": "Soporte — ticket 8842 (resuelto)",
    "is_favorite": true,
    "permission_mode": "auto",
    "model_id": 17,
    "created_at": "2026-09-01T14:02:11Z",
    "updated_at": "2026-09-01T14:09:44Z"
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Delete a chat

DELETEapi.niucore.com/api/v1/chats/{chat_id}

Scope: chat:write

Soft delete, same as in the application: the chat disappears on both sides.

Heads up

Deleted messages still count toward already-billed usage. Deleting a conversation does not erase what it cost.

Path

chat_idstring (uuid)required

Chat identifier.

curl -sS -X DELETE 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
    "deleted": true
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

List messages

GETapi.niucore.com/api/v1/chats/{chat_id}/messages

Scope: chat:read

Returns the chat's turns in chronological order. Each item carries prompt (what was sent) and content (what was answered).

Path

chat_idstring (uuid)required

Chat identifier.

Query

pageintegerdefaults to 1

Page number, starting at 1.

sizeintegerdefaults to 50

Items per page. Maximum 200.

Returns

idinteger

Turn identifier.

chat_idstring (uuid)

Chat it belongs to.

rolestring

Always assistant.

contentstring

The model's answer.

promptstring

What was sent. Only in the message listing.

statusstring

completed, cancelled, error or pending. In the history, an API turn that ended in message.cancelled reads cancelled.

usageobject

Turn usage: prompt_tokens, completion_tokens, total_tokens, reasoning_tokens (integers) plus model and provider. It is null if the turn consumed nothing. The shape is identical in the stream, the synchronous response, the replay and here.

stepsarray

Reasoning steps and tools executed: { key, label, label_code, status, timestamp, duration?, detail?, tokens?, tool_calls? }. Informational — the shape can grow, so read the fields you care about and ignore the rest.

sourcesarray

Library chunks used as context.

anonymizationobject | null

Replacements applied by incognito mode, if the company has it enabled.

metadataobject | null

The metadata the integrator sent with the turn, echoed verbatim.

created_atstring (date-time)

Creation timestamp.

curl -sS -X GET 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/messages?page=1&size=50' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": [
    {
      "id": 90211,
      "chat_id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
      "role": "assistant",
      "content": "El pedido 8842 se despachó el 28 de agosto y llegó el 1 de septiembre.",
      "prompt": "¿Qué pasó con el pedido 8842?",
      "status": "completed",
      "usage": {
        "prompt_tokens": 1840,
        "completion_tokens": 96,
        "total_tokens": 1936,
        "reasoning_tokens": 0,
        "provider": "OPENAI",
        "model": "gpt-4o"
      },
      "steps": [],
      "sources": [],
      "anonymization": null,
      "metadata": {
        "ticket": "8842"
      },
      "created_at": "2026-09-01T14:09:44Z"
    }
  ],
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77",
    "page": 1,
    "size": 50,
    "total": 1
  }
}

Send a turn

POSTapi.niucore.com/api/v1/chats/{chat_id}/messages

Scope: chat:write

Sends a message and blocks until the full answer. It only accepts permission_mode: "auto".

Idempotency-Key is required

Without the header the request is rejected with 400 api_v1_idempotency_key_required. One is never generated for you: that would turn every retry into a new turn — and a new charge.

A turn can take minutes. The server cuts it off after 30 minutes with 504; set your HTTP client timeout above that, or use the streaming send.

In manual mode the turn stops to ask for permission, and this channel has no way to answer it: that is why it is rejected with 409 instead of leaving the client waiting for something that never arrives. For manual, use the stream.

Path

chat_idstring (uuid)required

Chat identifier. If it does not exist, it is created with that id.

Headers

Idempotency-Keystringrequired

Unique identifier of the attempt. Retrying with the same key returns the same result without re-running the turn.

Request body

contentstringrequired

The message. 64,000 characters max.

model_idinteger

Model to use for this turn. Without it, the chat's or the company's.

permission_modestringdefaults to manual

On this endpoint it must be auto.

auto

attachmentsobject

Resources the turn attaches. Each type additionally requires the read scope of its resource.

workspace_idsinteger[]

Libraries. Requires libraries:read.

file_idsinteger[]

Files. Requires libraries:read.

skill_idsinteger[]

Skills. Requires skills:read.

mcp_server_idsinteger[]

Connectors. Requires connectors:use.

metadataobject

Your own data, to correlate on your side. Echoed verbatim and never sent to the model. 2048 serialized bytes max.

Returns

idinteger

Turn identifier.

chat_idstring (uuid)

Chat it belongs to.

rolestring

Always assistant.

contentstring

The model's answer.

promptstring

What was sent. Only in the message listing.

statusstring

completed, cancelled, error or pending. In the history, an API turn that ended in message.cancelled reads cancelled.

usageobject

Turn usage: prompt_tokens, completion_tokens, total_tokens, reasoning_tokens (integers) plus model and provider. It is null if the turn consumed nothing. The shape is identical in the stream, the synchronous response, the replay and here.

stepsarray

Reasoning steps and tools executed: { key, label, label_code, status, timestamp, duration?, detail?, tokens?, tool_calls? }. Informational — the shape can grow, so read the fields you care about and ignore the rest.

sourcesarray

Library chunks used as context.

anonymizationobject | null

Replacements applied by incognito mode, if the company has it enabled.

metadataobject | null

The metadata the integrator sent with the turn, echoed verbatim.

created_atstring (date-time)

Creation timestamp.

Errors

  • 400api_v1_idempotency_key_requiredThe Idempotency-Key header is missing.
  • 403api_token_scope_not_allowedA resource was attached without its read scope. data.required_scopes lists the missing ones.
  • 409api_v1_sync_requires_autopermission_mode is not auto.
  • 409api_v1_idempotency_conflictThe same key was previously used with a different body.
  • 409api_v1_turn_in_progressThe turn for that key is still running.
  • 409api_v1_chat_busyThat chat already has a turn running, whether from the API or from the application. data.message_id identifies which one.
  • 422api_v1_content_too_longcontent exceeds the maximum.
  • 422api_v1_too_many_attachmentsToo many attachments.
  • 502upstream_errorThe turn failed downstream. The message_code is the turn's code (upstream_error or one coming from the model) and data carries chat_id and message_id. It is the same body the key's replay returns.
  • 502interaction_in_auto_modeThe turn asked for an interaction (for example, connecting a connector) that the synchronous send cannot answer, and it was cut. Use the stream.
  • 504turn_timeoutThe turn exceeded its maximum duration and was cut. data carries chat_id and message_id.
  • 503api_v1_core_unavailableThe turn finished but its save could not be confirmed (data.code: "persistence_failed"). Check its state with the same key before retrying.
  • 409api_v1_core_unavailableAnother execution closed this turn (data.code: "idempotency_outcome_unknown"). Repeat the request with the same key to read the stored outcome.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/messages' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8f0a1c72-5c9e-4a1b-8f31-2d0b7c6e4a95" \
  -d '{
    "content": "Resumí el estado del pedido 8842 y decime si hay reclamos abiertos.",
    "permission_mode": "auto",
    "attachments": {
      "workspace_ids": [
        31
      ]
    },
    "metadata": {
      "ticket": "8842"
    }
  }'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "id": 90212,
    "chat_id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
    "role": "assistant",
    "content": "El pedido 8842 se despachó el 28 de agosto…",
    "status": "completed",
    "usage": {
      "prompt_tokens": 2410,
      "completion_tokens": 188,
      "total_tokens": 2598,
      "reasoning_tokens": 0,
      "provider": "OPENAI",
      "model": "gpt-4o"
    },
    "steps": [
      {
        "key": "search_documents",
        "label": "Buscando en tus bibliotecas",
        "label_code": "step.tool.running",
        "status": "completed",
        "timestamp": "2026-09-01T14:09:41Z",
        "duration": 1240
      }
    ],
    "sources": [
      {
        "workspace_id": 31,
        "file_id": 902,
        "score": 0.83
      }
    ],
    "anonymization": null,
    "metadata": {
      "ticket": "8842"
    }
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Send a turn (stream)

POSTapi.niucore.com/api/v1/chats/{chat_id}/messages/stream

Scope: chat:write

Same as the synchronous send, but returns Server-Sent Events as the turn progresses. It is the only path for permission_mode: "manual".

The response is text/event-stream. Each event carries event: and data: with a JSON payload. Every type is described in Stream events.

Note

The turn finishes even if the client disconnects: the message is persisted and the outcome is stored under the Idempotency-Key. Sending the same key again re-delivers that outcome without re-running anything.

Path

chat_idstring (uuid)required

Chat identifier. If it does not exist, it is created.

Headers

Idempotency-Keystringrequired

Unique identifier of the attempt.

Request body

contentstringrequired

The message.

model_idinteger

Turn model.

permission_modestringdefaults to manual

manual makes the turn ask for permission before running tools.

manualauto

attachmentsobject

Same as the synchronous send.

metadataobject

Your own data.

Errors

  • 409api_v1_chat_busyThat chat already has a turn running, whether from the API or from the application.
  • 409api_v1_idempotency_conflictThe key was used with a different body.
curl -sS -N -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/messages/stream' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: text/event-stream' \
  -H 'Idempotency-Key: 8f0a1c72-5c9e-4a1b-8f31-2d0b7c6e4a95' \
  -d '{
    "content": "Resumí el estado del pedido 8842.",
    "permission_mode": "manual",
    "attachments": { "workspace_ids": [31] }
  }'
Response
event: message.start
data: {"chat_id":"3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3","message_id":90213,"request_id":"9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"}

event: message.delta
data: {"text":"El pedido 8842","replace":false}

event: message.delta
data: {"text":" se despachó el 28 de agosto.","replace":false}

event: message.step
data: {"steps":[{"key":"search_documents","label":"Buscando en tus bibliotecas","label_code":"step.tool.running","status":"completed","timestamp":"2026-09-01T14:09:41Z","duration":1240}]}

event: ping
data: {"ts":1767222015.42}

event: message.completed
data: {"id":90213,"chat_id":"3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3","role":"assistant","content":"El pedido 8842 se despachó el 28 de agosto.","usage":{"prompt_tokens":2410,"completion_tokens":188,"total_tokens":2598,"provider":"OPENAI","model":"gpt-4o"},"steps":[],"sources":[],"anonymization":null,"metadata":{"ticket":"8842"}}

Chat catalog

GETapi.niucore.com/api/v1/chat/catalog

Scope: chat:read

What a turn of this credential can use: models, libraries, skills and connectors, already narrowed by the user's permissions and the credential's scope.

Note

Blocks are scope-conditional: a credential without libraries:read does not receive the libraries key — not empty, absent. An empty list would read as “there are none”, and that would be false.

Tip

Only COMPLETION models are returned. An embedding model never appears here: sending it as model_id would produce a turn that fails downstream.

Returns

modelsarray

Enabled models (id, name, code, type).

permission_modesstring[]

Always ["manual", "auto"].

librariesarray

Only with libraries:read.

skillsarray

Only with skills:read.

connectorsarray

Only with connectors:use.

curl -sS -X GET 'https://api.niucore.com/api/v1/chat/catalog' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN"
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "models": [
      {
        "id": 17,
        "name": "GPT-4o",
        "code": "gpt-4o",
        "type": "COMPLETION"
      },
      {
        "id": 23,
        "name": "Claude Sonnet",
        "code": "claude-sonnet-4",
        "type": "COMPLETION"
      }
    ],
    "permission_modes": [
      "manual",
      "auto"
    ],
    "libraries": [
      {
        "id": 31,
        "name": "Procedimientos de soporte"
      }
    ],
    "skills": [
      {
        "id": 147,
        "name": "Redactar respuesta a cliente"
      }
    ],
    "connectors": [
      {
        "id": 8,
        "name": "gmail",
        "display_name": "Gmail"
      }
    ]
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Approve tools

POSTapi.niucore.com/api/v1/chats/{chat_id}/actions/approve-tool

Scope: chat:write

Answers a message.action_required event of kind tool_approval: one decision per tool the turn asked to run.

The tool_use_id values come from payload.tools, where each entry is { tool_use_id, name, server, input }. The action_id is the one from the event: it is opaque and only valid for that turn and that credential.

Heads up

An interaction is resolved once and expires after 110 seconds. A second attempt returns 409.

Path

chat_idstring (uuid)required

The turn's chat.

Request body

action_idstringrequired

The event's action_id.

decisionsobject[]required

One decision per tool. At least one.

tool_use_idstringrequired

Tool id, from the payload.

approvedbooleanrequired

true runs it, false skips it.

Errors

  • 404api_v1_action_not_foundThe interaction does not exist, expired, or is not yours.
  • 409api_v1_action_not_pendingIt was already resolved, another request claimed it first, or its outcome is unknown. Do not retry it.
  • 409api_v1_action_result_unknownThe conversation service received the decision and rejected it (data.upstream_status). The interaction is closed: check the turn.
  • 503api_v1_service_unavailableThe decision never left (meta.error_details.retry_action: "retry"). The interaction goes back to pending: retrying is safe.
  • 503api_v1_action_result_unknownThe decision left and there was no answer: it is unknown whether it applied (retry_action: "check_status"). Do not resend it; follow the stream or list the messages.
  • 503api_v1_interaction_backend_unavailableInteractions cannot be resolved right now. It is not a 404: it is an outage, and retrying makes sense.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/approve-tool' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action_id": "act_9c2f1e7a4b6d",
    "decisions": [
      {
        "tool_use_id": "toolu_01A9f",
        "approved": true
      },
      {
        "tool_use_id": "toolu_01B3k",
        "approved": false
      }
    ]
  }'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "action_id": "act_9c2f1e7a4b6d",
    "state": "resolved"
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Respond to a plan

POSTapi.niucore.com/api/v1/chats/{chat_id}/actions/respond-plan

Scope: chat:write

Approves or rejects the plan the turn proposed (kind: "plan_approval").

When it arrives. No special mode is needed: a turn in manual or auto emits plan_approval when the model decides to call its planning tool before acting. Asking for it in the message — “before doing anything, propose a step-by-step plan and wait for my approval” — makes it likelier but does not guarantee it: the decision is the model's and depends on which one is configured. Treat this interaction as one that may appear, not one you can force. What does NOT exist in v1 is the application's permission_mode: "plan".

The plan travels in payload.plan: { title, context, steps, notes }, where each step is { step, action, tool? }. tool only appears if that step will use a tool.

Path

chat_idstring (uuid)required

The turn's chat.

Request body

action_idstringrequired

The event's action_id.

actionstringrequired

The decision.

approvereject

Errors

  • 404api_v1_action_not_foundThe interaction does not exist, expired, or is not yours.
  • 409api_v1_action_not_pendingIt was already resolved, another request claimed it first, or its outcome is unknown. Do not retry it.
  • 409api_v1_action_result_unknownThe conversation service received the decision and rejected it (data.upstream_status). The interaction is closed: check the turn.
  • 503api_v1_service_unavailableThe decision never left (meta.error_details.retry_action: "retry"). The interaction goes back to pending: retrying is safe.
  • 503api_v1_action_result_unknownThe decision left and there was no answer: it is unknown whether it applied (retry_action: "check_status"). Do not resend it; follow the stream or list the messages.
  • 503api_v1_interaction_backend_unavailableInteractions cannot be resolved right now. It is not a 404: it is an outage, and retrying makes sense.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/respond-plan' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action_id": "act_4d8b2c0f9e11",
    "action": "approve"
  }'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "action_id": "act_4d8b2c0f9e11",
    "state": "resolved"
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Answer a question

POSTapi.niucore.com/api/v1/chats/{chat_id}/actions/respond-elicitation

Scope: chat:write

Answers the question the turn asked (kind: "elicitation"). This is MCP protocol elicitation: it is raised by a connector, not by a native NiuCore tool.

The interaction payload is { message, mode, requested_schema }. requested_schema is a JSON Schema and content must be a flat object satisfying it: its properties are the fields the connector asks for, not a list of options.

Path

chat_idstring (uuid)required

The turn's chat.

Request body

action_idstringrequired

The event's action_id.

actionstringrequired

accept answers, decline refuses, cancel aborts the question.

acceptdeclinecancel

contentobject

The answer. A flat object satisfying payload.requested_schema. Required with action: "accept".

Errors

  • 404api_v1_action_not_foundThe interaction does not exist, expired, or is not yours.
  • 409api_v1_action_not_pendingIt was already resolved, another request claimed it first, or its outcome is unknown. Do not retry it.
  • 409api_v1_action_result_unknownThe conversation service received the decision and rejected it (data.upstream_status). The interaction is closed: check the turn.
  • 503api_v1_service_unavailableThe decision never left (meta.error_details.retry_action: "retry"). The interaction goes back to pending: retrying is safe.
  • 503api_v1_action_result_unknownThe decision left and there was no answer: it is unknown whether it applied (retry_action: "check_status"). Do not resend it; follow the stream or list the messages.
  • 503api_v1_interaction_backend_unavailableInteractions cannot be resolved right now. It is not a 404: it is an outage, and retrying makes sense.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/respond-elicitation' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action_id": "act_11ff03ac7d52",
    "action": "accept",
    "content": {
      "email": "ada@acme.test"
    }
  }'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "action_id": "act_11ff03ac7d52",
    "state": "resolved"
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Cancel a pending connection

POSTapi.niucore.com/api/v1/chats/{chat_id}/actions/cancel-auth

Scope: chat:write

Unblocks a turn stopped on kind: "auth_required" without connecting anything. The model continues without that tool.

There is no public confirm-auth

Completing a connector's OAuth requires a browser and a person, and that happens in the application. From the API you can only cancel, or ask the user to connect the service in NiuCore.

Path

chat_idstring (uuid)required

The turn's chat.

Request body

action_idstringrequired

The event's action_id.

Errors

  • 404api_v1_action_not_foundThe interaction does not exist, expired, or is not yours.
  • 409api_v1_action_not_pendingIt was already resolved, another request claimed it first, or its outcome is unknown. Do not retry it.
  • 409api_v1_action_result_unknownThe conversation service received the decision and rejected it (data.upstream_status). The interaction is closed: check the turn.
  • 503api_v1_service_unavailableThe decision never left (meta.error_details.retry_action: "retry"). The interaction goes back to pending: retrying is safe.
  • 503api_v1_action_result_unknownThe decision left and there was no answer: it is unknown whether it applied (retry_action: "check_status"). Do not resend it; follow the stream or list the messages.
  • 503api_v1_interaction_backend_unavailableInteractions cannot be resolved right now. It is not a 404: it is an outage, and retrying makes sense.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/cancel-auth' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action_id": "act_7b1e5f30ca84"
  }'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "action_id": "act_7b1e5f30ca84",
    "state": "resolved"
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}

Cancel the turn

POSTapi.niucore.com/api/v1/chats/{chat_id}/actions/cancel

Scope: chat:write

Stops the chat's running turn. Without action_id it cancels the live turn, which is the usual case when aborting.

Tip

It is idempotent: cancelling a turn that already finished still answers 200. A client retrying because it missed the answer should not have to tell “I cancelled it” from “it was already cancelled”.

A 200 means the cancellation was delivered. If it could not be delivered you get 502 and the turn keeps running: retry, and keep reading the stream meanwhile. A cancelled turn ends with message.cancelled, and replaying that Idempotency-Key returns status: "cancelled".

Path

chat_idstring (uuid)required

The chat to cancel.

Request body

action_idstring

Optional. With it, the interaction must belong to this credential's turn.

Errors

  • 404api_v1_not_foundThe chat does not exist or belongs to another credential. Cancelling does not create the chat, unlike sending a turn.
  • 502api_v1_core_unavailableThe cancellation could not be delivered to the turn. The turn keeps running: retry.
curl -sS -X POST 'https://api.niucore.com/api/v1/chats/3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3/actions/cancel' \
  -H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
Response
{
  "status": "success",
  "message": "Operación exitosa",
  "message_code": "api_v1_ok",
  "data": {
    "chat_id": "3f6b1a90-6c2d-4d84-a0b1-9d0f5e7c2ab3",
    "cancelled": true
  },
  "meta": {
    "request_id": "9f1c0a3e-7b2d-4f18-9a55-2c6e0d1b4a77"
  }
}