{
  "openapi": "3.1.0",
  "info": {
    "title": "Agent Rails Public Agent API",
    "version": "1.0.0",
    "description": "Send an end-user message to an Agent Rails AI agent and receive the agent's reply. Human-readable docs (Russian): https://agent-rails.ru/docs/api. Server-to-server only: never expose the API key in browser or mobile code.",
    "contact": { "email": "support@agent-rails.ru" }
  },
  "servers": [{ "url": "https://agent-rails.ru/api/public/v1" }],
  "security": [{ "bearerAuth": [] }, { "apiKeyHeader": [] }],
  "paths": {
    "/agents": {
      "get": {
        "operationId": "listAgents",
        "summary": "Agents of the key owner with API access enabled",
        "responses": {
          "200": {
            "description": "Agents",
            "content": { "application/json": { "schema": {
              "type": "object",
              "required": ["agents"],
              "properties": { "agents": { "type": "array", "items": { "$ref": "#/components/schemas/Agent" } } }
            } } }
          },
          "401": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/agents/{agent_id}/messages": {
      "post": {
        "operationId": "sendMessage",
        "summary": "Store an end-user message and get the agent's reply",
        "description": "Business outcomes are always HTTP 200 with a flat MessageResult; see `status`. Consumes 1 message credit per AI reply.",
        "parameters": [
          { "$ref": "#/components/parameters/AgentId" },
          { "name": "Idempotency-Key", "in": "header", "required": false, "schema": { "type": "string", "pattern": "^[A-Za-z0-9_.:-]{1,128}$" } }
        ],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageRequest" } } }
        },
        "responses": {
          "200": { "description": "Outcome", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageResult" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "422": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" },
          "503": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/agents/{agent_id}/messages/{message_id}/reply": {
      "get": {
        "operationId": "getReply",
        "summary": "Poll the reply to a stored user message (after status=pending)",
        "description": "Never generates and never consumes credits. `no_reply` with reason `not_answered` means no reply is coming.",
        "parameters": [
          { "$ref": "#/components/parameters/AgentId" },
          { "name": "message_id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Outcome", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessageResult" } } } },
          "401": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/agents/{agent_id}/conversations/{user_id}/messages": {
      "get": {
        "operationId": "getHistory",
        "summary": "Conversation history of one end user, oldest first",
        "parameters": [
          { "$ref": "#/components/parameters/AgentId" },
          { "name": "user_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "after_seq", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0 } },
          { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }
        ],
        "responses": {
          "200": {
            "description": "History page",
            "content": { "application/json": { "schema": {
              "type": "object",
              "required": ["conversation_id", "messages", "next_after_seq"],
              "properties": {
                "conversation_id": { "type": "string", "description": "Empty when the user has no conversation yet" },
                "messages": { "type": "array", "items": { "$ref": "#/components/schemas/HistoryMessage" } },
                "next_after_seq": { "type": "integer" }
              }
            } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Authorization: Bearer ar_…" },
      "apiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }
    },
    "parameters": {
      "AgentId": { "name": "agent_id", "in": "path", "required": true, "schema": { "type": "string" } }
    },
    "responses": {
      "Error": {
        "description": "Request error",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Agent": {
        "type": "object",
        "required": ["id", "name"],
        "properties": { "id": { "type": "string" }, "name": { "type": "string" } }
      },
      "MessageRequest": {
        "type": "object",
        "required": ["user", "message"],
        "properties": {
          "user": {
            "type": "object",
            "required": ["id"],
            "properties": {
              "id": { "type": "string", "pattern": "^[A-Za-z0-9_.:@-]{1,128}$", "description": "Stable end-user id in the caller's system" },
              "name": { "type": "string", "maxLength": 100 }
            }
          },
          "message": { "type": "string", "minLength": 1, "maxLength": 32000 },
          "context": { "type": "string", "maxLength": 8000, "description": "Sent to the agent when it changes" },
          "metadata": {
            "type": "object",
            "maxProperties": 20,
            "propertyNames": { "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$" },
            "additionalProperties": { "type": "string", "maxLength": 512 },
            "description": "Shown to the operator; never sent to the agent"
          },
          "timeout_seconds": { "type": "integer", "minimum": 1, "maximum": 55, "default": 25 },
          "idempotency_key": { "type": "string", "pattern": "^[A-Za-z0-9_.:-]{1,128}$" }
        }
      },
      "MessageResult": {
        "type": "object",
        "required": ["status", "reply", "reply_id", "message_id", "seq", "conversation_id", "reason"],
        "properties": {
          "status": { "type": "string", "enum": ["completed", "pending", "merged", "no_reply"] },
          "reply": { "type": "string", "description": "Agent text; non-empty only when status=completed" },
          "reply_id": { "type": "string" },
          "message_id": { "type": "string", "description": "Stored user message id (poll key)" },
          "seq": { "type": "integer" },
          "conversation_id": { "type": "string" },
          "reason": {
            "type": "string",
            "enum": ["", "paused", "stopped", "off_hours", "agent_inactive", "insufficient_balance", "unavailable", "not_answered"]
          }
        }
      },
      "HistoryMessage": {
        "type": "object",
        "required": ["seq", "id", "role", "text", "is_manual", "created_at"],
        "properties": {
          "seq": { "type": "integer" },
          "id": { "type": "string" },
          "role": { "type": "string", "enum": ["user", "assistant"] },
          "text": { "type": "string" },
          "is_manual": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": {
                "type": "string",
                "enum": ["validation_error", "unauthorized", "plan_required", "agent_not_found", "message_not_found", "idempotency_key_reused", "rate_limited", "busy", "internal_error", "unavailable"]
              },
              "message": { "type": "string" }
            }
          }
        }
      }
    }
  }
}
