{
  "openapi": "3.1.0",
  "info": {
    "title": "RSX State",
    "version": "v1",
    "description": "Persistent state and audit history for services that outlive the container they run in."
  },
  "servers": [
    {
      "url": "https://api.rsx.group"
    }
  ],
  "components": {
    "schemas": {
      "AuditEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "0198f2b1-6c2a-7c9e-9d3a-1e2f3a4b5c6d"
          },
          "source": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
            "example": "roxy"
          },
          "scope": {
            "type": [
              "string",
              "null"
            ],
            "example": "guild:123456789"
          },
          "actor": {
            "type": [
              "string",
              "null"
            ],
            "example": "user:987654321"
          },
          "action": {
            "type": "string",
            "example": "member.ban"
          },
          "target": {
            "type": [
              "string",
              "null"
            ],
            "example": "user:456789123"
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {},
            "example": {
              "reason": "Spam"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-09-01T14:30:00.000Z"
          }
        },
        "required": [
          "id",
          "source",
          "scope",
          "actor",
          "action",
          "target",
          "metadata",
          "createdAt"
        ]
      },
      "StateEntry": {
        "type": "object",
        "properties": {
          "namespace": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
            "example": "roxy"
          },
          "key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "pattern": "^\\S(?:[^\\x00-\\x1f\\x7f]*\\S)?$",
            "example": "guild:123456789"
          },
          "value": {
            "description": "Any JSON value. At most 32 KiB once serialised."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-09-01T14:30:00.000Z"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-09-01T14:30:00.000Z"
          }
        },
        "required": [
          "namespace",
          "key",
          "value",
          "createdAt",
          "updatedAt"
        ]
      },
      "StateOwner": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "namespace",
              "source"
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
            "example": "roxy"
          },
          "apiKeyId": {
            "type": "string",
            "example": "0198f2b1-6c2a-7c9e-9d3a-1e2f3a4b5c6d"
          },
          "claimedAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-09-01T14:30:00.000Z"
          }
        },
        "required": [
          "kind",
          "name",
          "apiKeyId",
          "claimedAt"
        ]
      },
      "UpdateStateOwner": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "namespace",
              "source"
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
            "example": "roxy"
          },
          "apiKeyId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          }
        },
        "required": [
          "kind",
          "name",
          "apiKeyId"
        ]
      },
      "UpdateState": {
        "type": "object",
        "properties": {
          "namespace": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
            "example": "roxy"
          },
          "key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "pattern": "^\\S(?:[^\\x00-\\x1f\\x7f]*\\S)?$",
            "example": "guild:123456789"
          },
          "value": {
            "description": "Any JSON value. At most 32 KiB once serialised."
          }
        },
        "required": [
          "namespace",
          "key",
          "value"
        ]
      },
      "RemoveState": {
        "type": "object",
        "properties": {
          "namespace": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
            "example": "roxy"
          },
          "key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "pattern": "^\\S(?:[^\\x00-\\x1f\\x7f]*\\S)?$",
            "example": "guild:123456789"
          }
        },
        "required": [
          "namespace",
          "key"
        ]
      },
      "AddAuditEvent": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
            "example": "roxy"
          },
          "scope": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 256,
            "example": "guild:123456789"
          },
          "actor": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 256,
            "example": "user:987654321"
          },
          "action": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "member.ban"
          },
          "target": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 256,
            "example": "user:456789123"
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {},
            "example": {
              "reason": "Spam"
            }
          }
        },
        "required": [
          "source",
          "action"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/state/v1/admin/audit/list": {
      "get": {
        "operationId": "adminListAuditEvents",
        "summary": "Audit events across every source, newest first",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
              "example": "roxy"
            },
            "required": false,
            "name": "source",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "required": false,
            "name": "scope",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "required": false,
            "name": "actor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 128
            },
            "required": false,
            "name": "action",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "required": false,
            "name": "target",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "example": "2026-09-01T00:00:00.000Z"
            },
            "required": false,
            "name": "before",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "example": "2026-08-01T00:00:00.000Z"
            },
            "required": false,
            "name": "after",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "example": 20
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Audit events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditEvent"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "cursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/admin/audit/get": {
      "get": {
        "operationId": "adminGetAuditEvent",
        "summary": "One audit event, whoever produced it",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The audit event",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AuditEvent"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/admin/state/list": {
      "get": {
        "operationId": "adminListState",
        "summary": "State entries across every namespace, or within one",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
              "example": "roxy"
            },
            "required": false,
            "name": "namespace",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50,
              "example": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "State entries, ordered by namespace then key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StateEntry"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "cursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/admin/state/get": {
      "get": {
        "operationId": "adminGetState",
        "summary": "One state entry, in any namespace",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
              "example": "roxy"
            },
            "required": true,
            "name": "namespace",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256,
              "pattern": "^\\S(?:[^\\x00-\\x1f\\x7f]*\\S)?$",
              "example": "guild:123456789"
            },
            "required": true,
            "name": "key",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The state entry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/StateEntry"
                        },
                        {
                          "required": [
                            "namespace",
                            "key",
                            "createdAt",
                            "updatedAt"
                          ]
                        }
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/admin/owners/list": {
      "get": {
        "operationId": "adminListStateOwners",
        "summary": "Every claimed namespace and audit source, and the key holding it",
        "tags": [
          "admin"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "namespace",
                "source"
              ]
            },
            "required": false,
            "name": "kind",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50,
              "example": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Ownership records",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StateOwner"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "cursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/admin/owners/update": {
      "post": {
        "operationId": "adminUpdateStateOwner",
        "summary": "Reassign a namespace or audit source to a different API key",
        "tags": [
          "admin"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateStateOwner"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The ownership record, as it now stands",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/StateOwner"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/state/get": {
      "get": {
        "operationId": "getState",
        "summary": "Read one persistent state value",
        "tags": [
          "state"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
              "example": "roxy"
            },
            "required": true,
            "name": "namespace",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256,
              "pattern": "^\\S(?:[^\\x00-\\x1f\\x7f]*\\S)?$",
              "example": "guild:123456789"
            },
            "required": true,
            "name": "key",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The state entry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/StateEntry"
                        },
                        {
                          "required": [
                            "namespace",
                            "key",
                            "createdAt",
                            "updatedAt"
                          ]
                        }
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/state/list": {
      "get": {
        "operationId": "listState",
        "summary": "List persistent state within a namespace",
        "tags": [
          "state"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
              "example": "roxy"
            },
            "required": true,
            "name": "namespace",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "example": 20
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "State entries, ordered by key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/StateEntry"
                          },
                          {
                            "required": [
                              "namespace",
                              "key",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        ]
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "cursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/state/update": {
      "post": {
        "operationId": "updateState",
        "summary": "Create or replace a persistent state value",
        "tags": [
          "state"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateState"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The stored entry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/StateEntry"
                        },
                        {
                          "required": [
                            "namespace",
                            "key",
                            "createdAt",
                            "updatedAt"
                          ]
                        }
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/state/remove": {
      "post": {
        "operationId": "removeState",
        "summary": "Delete a persistent state value",
        "tags": [
          "state"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveState"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The entry that was removed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "namespace": {
                          "type": "string"
                        },
                        "key": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "namespace",
                        "key"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/audit/add": {
      "post": {
        "operationId": "addAuditEvent",
        "summary": "Record an audit event",
        "tags": [
          "audit"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddAuditEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The recorded event, with the timestamp this service assigned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AuditEvent"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/audit/list": {
      "get": {
        "operationId": "listAuditEvents",
        "summary": "Query audit events, newest first",
        "tags": [
          "audit"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9-]*(:[a-z0-9-]+)*$",
              "example": "roxy"
            },
            "required": false,
            "name": "source",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "required": false,
            "name": "scope",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "required": false,
            "name": "actor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 128
            },
            "required": false,
            "name": "action",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "required": false,
            "name": "target",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "example": "2026-09-01T00:00:00.000Z"
            },
            "required": false,
            "name": "before",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "example": "2026-08-01T00:00:00.000Z"
            },
            "required": false,
            "name": "after",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "example": 20
            },
            "required": false,
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Audit events, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditEvent"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "cursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/state/v1/audit/get": {
      "get": {
        "operationId": "getAuditEvent",
        "summary": "Read one audit event",
        "tags": [
          "audit"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "required": true,
            "name": "id",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The audit event",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AuditEvent"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {}
}
