{
  "openapi": "3.1.0",
  "info": {
    "title": "Agentropy Service API",
    "version": "0.1.0",
    "description": "Tenant-scoped durable agent messages. Service credentials belong on customer backends. Idempotency is retained until terminal receipt retention pruning (default minimum 30 days)."
  },
  "security": [
    {
      "ServiceKey": []
    }
  ],
  "paths": {
    "/v1/agents/{agent_id}/messages": {
      "post": {
        "operationId": "submitMessage",
        "summary": "Commit a message and return a receipt",
        "description": "Requires messages:write and ownership of the agent namespace. A duplicate retained key returns the original receipt. Handler execution may precede response. Tenant scope is derived solely from the verified key.",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255,
              "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,62}:[A-Za-z0-9][A-Za-z0-9_:.-]*$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Use a stable key on EVERY retry of the same logical operation.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:-]{1,200}$"
            }
          },
          {
            "name": "Agentropy-Agent-Type",
            "in": "header",
            "description": "Configured type name for creation; must be tenant-allowed. Existing agent types cannot change.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "type": "set",
                "payload": {
                  "key": "favorite_city",
                  "value": "Madrid"
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Committed acceptance or existing retained receipt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Poll this authenticated URL",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid identity, message, key or configured agent type"
          },
          "401": {
            "description": "Missing, invalid, expired or revoked credential"
          },
          "403": {
            "description": "Credential permission or agent-type grant denied"
          },
          "404": {
            "description": "Missing resource or namespace outside authenticated tenant"
          },
          "409": {
            "description": "Idempotency payload or agent type conflict"
          },
          "413": {
            "description": "Payload or initial state exceeds tenant limit"
          },
          "429": {
            "description": "Rate, agent-count or inbox quota exhausted"
          },
          "503": {
            "description": "Unavailable; acceptance outcome can be unknown. Retry with the SAME idempotency key."
          }
        }
      }
    },
    "/v1/agents/{agent_id}/messages/{message_id}": {
      "get": {
        "operationId": "getMessage",
        "summary": "Read a stored result without activating an agent",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255,
              "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,62}:[A-Za-z0-9][A-Za-z0-9_:.-]*$"
            }
          },
          {
            "name": "message_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stored receipt; handler failures appear as failed status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                }
              }
            }
          },
          "400": {
            "description": "Invalid identity, message, key or configured agent type"
          },
          "401": {
            "description": "Missing, invalid, expired or revoked credential"
          },
          "403": {
            "description": "Credential permission or agent-type grant denied"
          },
          "404": {
            "description": "Missing resource or namespace outside authenticated tenant"
          },
          "429": {
            "description": "Rate, agent-count or inbox quota exhausted"
          },
          "503": {
            "description": "Unavailable; acceptance outcome can be unknown. Retry with the SAME idempotency key."
          }
        }
      }
    },
    "/health/live": {
      "get": {
        "operationId": "liveness",
        "security": [],
        "responses": {
          "200": {
            "description": "HTTP process is live"
          }
        }
      }
    },
    "/health/ready": {
      "get": {
        "operationId": "readiness",
        "description": "Requires operations:read. Checks database, migration and core processes.",
        "responses": {
          "200": {
            "description": "Ready"
          },
          "401": {
            "description": "Missing, invalid, expired or revoked credential"
          },
          "403": {
            "description": "Credential permission or agent-type grant denied"
          },
          "503": {
            "description": "Not ready"
          }
        }
      }
    },
    "/v1/operations/inbox": {
      "get": {
        "operationId": "inboxHealth",
        "description": "Requires operations:read. Returns counts/oldest unfinished age only for the authenticated tenant.",
        "responses": {
          "200": {
            "description": "Tenant operational snapshot"
          },
          "401": {
            "description": "Missing, invalid, expired or revoked credential"
          },
          "403": {
            "description": "Credential permission or agent-type grant denied"
          },
          "429": {
            "description": "Rate, agent-count or inbox quota exhausted"
          },
          "503": {
            "description": "Unavailable; acceptance outcome can be unknown. Retry with the SAME idempotency key."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ServiceKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Agentropy-issued agt_<UUID>.<secret> service credential. Never embed in mobile apps or URLs."
      }
    },
    "schemas": {
      "Receipt": {
        "type": "object",
        "required": [
          "message_id",
          "agent_id",
          "status",
          "attempt"
        ],
        "properties": {
          "message_id": {
            "type": "string",
            "format": "uuid"
          },
          "agent_id": {
            "type": "string"
          },
          "status": {
            "enum": [
              "pending",
              "processing",
              "completed",
              "failed"
            ]
          },
          "attempt": {
            "type": "integer",
            "minimum": 0
          },
          "reply": {},
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          },
          "processed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      }
    }
  }
}
