{
  "openapi": "3.0.3",
  "info": {
    "title": "Auth Center Machine Artifacts",
    "version": "1.0.0",
    "description": "Application-scoped bearer API. Stable publication requires the existing administrator UI and session/CSRF API. All data is wrapped in the standard envelope."
  },
  "servers": [
    {
      "url": "/api/v1"
    }
  ],
  "security": [
    {
      "machineToken": []
    }
  ],
  "paths": {
    "/admin/release-tokens": {
      "get": {
        "operationId": "listReleaseTokens",
        "summary": "List redacted credentials (release-tokens:write)",
        "security": [
          {
            "adminSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ApplicationQuery"
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope with data=array of Token, never raw tokens or hashes"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createReleaseToken",
        "summary": "Create one application credential; raw token shown once (release-tokens:write)",
        "security": [
          {
            "adminSession": [],
            "csrfCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Origin"
          },
          {
            "$ref": "#/components/parameters/CSRF"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "application_id",
                  "name",
                  "scopes",
                  "expires_at"
                ],
                "properties": {
                  "application_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  },
                  "scopes": {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "enum": [
                        "releases:read",
                        "releases:create",
                        "uploads:write",
                        "publish:development",
                        "publish:staging"
                      ]
                    }
                  },
                  "expires_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Future, at most 90 days from now"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Credential"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/admin/release-tokens/{token}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TokenID"
        }
      ],
      "delete": {
        "operationId": "revokeReleaseToken",
        "summary": "Revoke a token immediately for future requests",
        "security": [
          {
            "adminSession": [],
            "csrfCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Origin"
          },
          {
            "$ref": "#/components/parameters/CSRF"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/admin/release-tokens/{token}/rotate": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TokenID"
        }
      ],
      "post": {
        "operationId": "rotateReleaseToken",
        "summary": "Atomically revoke old token and create a replacement with same scopes and expiry",
        "security": [
          {
            "adminSession": [],
            "csrfCookie": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Origin"
          },
          {
            "$ref": "#/components/parameters/CSRF"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Credential"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/admin/release-tokens/audit": {
      "get": {
        "operationId": "listMachineReleaseAudit",
        "summary": "Read machine request intent and result (release-tokens:write)",
        "security": [
          {
            "adminSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ApplicationQuery"
          },
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope with data=array of id, token_id, application_id, route, object_id, outcome, created_at. outcome=0 is interrupted/unknown."
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        }
      ],
      "post": {
        "operationId": "createMachineRelease",
        "summary": "Create or replay a draft (releases:create)",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._-]{1,128}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Manifest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Same release and current state for matching application/key/manifest",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Release"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        },
        {
          "$ref": "#/components/parameters/ReleaseID"
        }
      ],
      "get": {
        "operationId": "machineReleaseStatus",
        "summary": "Read release, build and upload state (releases:read)",
        "responses": {
          "200": {
            "description": "Upload sessions never expose storage secrets or object keys",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "release": {
                              "$ref": "#/components/schemas/Release"
                            },
                            "assets": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/Asset"
                              }
                            },
                            "build": {
                              "type": "object",
                              "properties": {
                                "git_commit": {
                                  "type": "string"
                                },
                                "metadata": {
                                  "type": "object",
                                  "additionalProperties": {
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            "production_approval_required": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases/{id}/uploads": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        },
        {
          "$ref": "#/components/parameters/ReleaseID"
        }
      ],
      "post": {
        "operationId": "startMachineUpload",
        "summary": "Create or resume an exact matching session (uploads:write)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "filename",
                  "size",
                  "sha256",
                  "revision"
                ],
                "properties": {
                  "filename": {
                    "type": "string",
                    "maxLength": 128,
                    "description": "ASCII basename; zip/apk/exe/msi/dmg/deb/rpm/appimage"
                  },
                  "size": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1,
                    "maximum": 134217728
                  },
                  "sha256": {
                    "type": "string",
                    "pattern": "^[a-f0-9]{64}$"
                  },
                  "revision": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session valid 24 hours; repeat metadata to resume",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "asset": {
                              "$ref": "#/components/schemas/Asset"
                            },
                            "part_size": {
                              "type": "integer",
                              "example": 33554432
                            },
                            "uploaded_parts": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "part_number": {
                                    "type": "integer"
                                  },
                                  "size": {
                                    "type": "integer",
                                    "format": "int64"
                                  },
                                  "sha256": {
                                    "type": "string",
                                    "description": "Base64 or empty if provider does not return it"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases/{id}/uploads/{asset}/part": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        },
        {
          "$ref": "#/components/parameters/ReleaseID"
        },
        {
          "$ref": "#/components/parameters/AssetID"
        }
      ],
      "post": {
        "operationId": "signMachineUploadPart",
        "summary": "Sign one 32 MiB part, or smaller final part (uploads:write)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "part_number",
                  "sha256"
                ],
                "properties": {
                  "part_number": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 4
                  },
                  "sha256": {
                    "type": "string",
                    "format": "byte",
                    "description": "SHA-256 digest encoded as Base64"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PUT file bytes to URL with all returned headers; do not send the machine Token to S3",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Envelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "url": {
                              "type": "string",
                              "format": "uri",
                              "description": "Secret capability valid at most 15 minutes; do not log"
                            },
                            "headers": {
                              "type": "object",
                              "additionalProperties": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases/{id}/uploads/{asset}/file": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        },
        {
          "$ref": "#/components/parameters/ReleaseID"
        },
        {
          "$ref": "#/components/parameters/AssetID"
        }
      ],
      "post": {
        "operationId": "uploadSmallMachineFile",
        "summary": "Upload a single file at most 32 MiB (uploads:write)",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "uploaded=true, completion_required=true; call complete before publication",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases/{id}/uploads/{asset}/complete": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        },
        {
          "$ref": "#/components/parameters/ReleaseID"
        },
        {
          "$ref": "#/components/parameters/AssetID"
        }
      ],
      "post": {
        "operationId": "completeMachineUpload",
        "summary": "Merge and synchronously verify full digest and file policy (uploads:write)",
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases/{id}/uploads/{asset}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        },
        {
          "$ref": "#/components/parameters/ReleaseID"
        },
        {
          "$ref": "#/components/parameters/AssetID"
        }
      ],
      "delete": {
        "operationId": "cancelMachineUpload",
        "summary": "Queue unfinished upload cleanup (uploads:write)",
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/automation/applications/{application}/releases/{id}/state": {
      "parameters": [
        {
          "$ref": "#/components/parameters/Application"
        },
        {
          "$ref": "#/components/parameters/ReleaseID"
        }
      ],
      "post": {
        "operationId": "publishOrCancelMachineRelease",
        "summary": "alpha requires publish:development; beta requires publish:staging; stable always denied",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "action",
                  "revision"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "publish",
                      "cancel"
                    ]
                  },
                  "revision": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "machineToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "acr_256-bit-random"
      },
      "adminSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "ac_access"
      },
      "csrfCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "ac_csrf"
      }
    },
    "parameters": {
      "ApplicationQuery": {
        "in": "query",
        "name": "application_id",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "TokenID": {
        "in": "path",
        "name": "token",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "Origin": {
        "in": "header",
        "name": "Origin",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Must exactly match APP_ORIGIN"
      },
      "CSRF": {
        "in": "header",
        "name": "X-CSRF-Token",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 32
        },
        "description": "Must match ac_csrf cookie"
      },
      "Application": {
        "in": "path",
        "name": "application",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ReleaseID": {
        "in": "path",
        "name": "id",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "AssetID": {
        "in": "path",
        "name": "asset",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "responses": {
      "Credential": {
        "description": "Store token immediately in a secret manager; it cannot be read again",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Envelope"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "token": {
                          "type": "string",
                          "pattern": "^acr_[A-Za-z0-9_-]{43}$"
                        },
                        "credential": {
                          "$ref": "#/components/schemas/Token"
                        }
                      }
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "Success": {
        "description": "Success with data=null. GET state for current revision before next mutation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Envelope"
            }
          }
        }
      },
      "Error": {
        "description": "400/40000 input or integrity; 401/40100 credentials; 403/40300 authorization; 404/40400 missing; 409/40900 conflict; 429/42900 rate/quota; 503/50300 unavailable. Retry-After may be present on capacity or rate errors.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "code",
                "message"
              ],
              "properties": {
                "code": {
                  "type": "integer"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Token": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "application_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": "string",
            "description": "Space-separated scope list"
          },
          "created_by": {
            "type": "string",
            "format": "uuid"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "revoked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Envelope": {
        "type": "object",
        "required": [
          "code",
          "message",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "enum": [
              0
            ]
          },
          "message": {
            "type": "string",
            "example": "success"
          },
          "data": {
            "nullable": true
          }
        }
      },
      "Manifest": {
        "type": "object",
        "required": [
          "version",
          "version_code",
          "platform",
          "arch",
          "channel",
          "git_commit"
        ],
        "properties": {
          "version": {
            "type": "string",
            "pattern": "^[0-9A-Za-z][0-9A-Za-z.+_-]{0,63}$"
          },
          "version_code": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "platform": {
            "type": "string",
            "enum": [
              "windows",
              "macos",
              "linux",
              "android",
              "ios"
            ]
          },
          "arch": {
            "type": "string",
            "enum": [
              "x64",
              "arm64",
              "x86",
              "universal"
            ]
          },
          "channel": {
            "type": "string",
            "enum": [
              "alpha",
              "beta",
              "stable"
            ]
          },
          "git_commit": {
            "type": "string",
            "pattern": "^(?:[a-f0-9]{40}|[a-f0-9]{64})$"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "JSON representation at most 16 KiB; no secrets"
          },
          "notes": {
            "type": "string",
            "maxLength": 10000
          }
        }
      },
      "Release": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "application_id": {
            "type": "string",
            "format": "uuid"
          },
          "version": {
            "type": "string"
          },
          "version_code": {
            "type": "integer",
            "format": "int64"
          },
          "platform": {
            "type": "string"
          },
          "arch": {
            "type": "string"
          },
          "channel": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "mandatory": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "scheduled",
              "published",
              "cancelled",
              "deleted"
            ]
          },
          "revision": {
            "type": "integer",
            "format": "int64"
          },
          "asset_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "ever_published": {
            "type": "boolean"
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "scheduled_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Asset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "release_id": {
            "type": "string",
            "format": "uuid"
          },
          "filename": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "format": "int64"
          },
          "sha256": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "uploading",
              "ready",
              "deleting",
              "deleted"
            ]
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}
