OpenAPI 3.1.0

AI Code Review Server API

Version 1.0.0

Canonical API for submitting PHP and Drupal code reviews. Each review executes through a provider profile the calling site registered on the administrator-only control plane; a request never carries a provider credential, upstream, header, route, or raw model identifier.

YAML source | JSON representation

Operations

MethodPathOperationSummaryAuthenticationRequestParametersResponses
GET/healthzgetLivenessCheck whether the Drupal request path is aliveNoneNoneNone
  • 200 The server process is alive: application/json HealthStatus
GET/readyzgetReadinessCheck configured review traffic and enabled language sidecar readinessNoneNoneNone
  • 200 The server is ready for review traffic: application/json HealthStatus
  • 503 The server or its enabled language sidecar is not ready for review traffic: application/json HealthStatus
POST/api/ai-code-review/v1/reviewscreateReviewSubmit a repository change for reviewbearerAuthapplication/json (required ReviewRequest)header:X-Request-ID, header:Idempotency-Key, header:Prefer
  • 200 Synchronous review completed: application/json ReviewResult Headers: X-Request-ID
  • 202 Review submission accepted for asynchronous processing or returned for an idempotent retry: application/json ReviewJob Headers: Location, Preference-Applied, X-Request-ID
  • 400 Malformed framing, malformed JSON, or duplicate properties within structural limits: application/json ErrorResponse Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 409 Idempotency conflict or incompatible repository state: application/json ErrorResponse Headers: X-Request-ID
  • 413 Request, repository, or diff exceeds a limit evaluated before duplicate detection: application/json ErrorResponse Headers: X-Request-ID
  • 415 The request content type or content encoding is not supported: application/json ErrorResponse Headers: X-Request-ID
  • 422 Depth, request fields, or Git references fail validation: application/json ErrorResponse Headers: X-Request-ID
  • 429 Per-client rate or concurrency limit, or asynchronous review backlog capacity, was exceeded: application/json ErrorResponse Headers: Retry-After, X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
  • 502 APISIX or an LLM provider returned an invalid response, or an enabled private language analyzer returned malformed output or failed its tool. No analyzer path, source, tool output, or private sidecar outcome is returned.: application/json ErrorResponse Headers: X-Request-ID
  • 503 Review service or a required dependency is unavailable, including an enabled language analyzer whose compatible sidecar is not ready. Disabled review submission uses the canonical service_unavailable code after authentication and route permission, without accepting work.: application/json ErrorResponse Headers: Retry-After, X-Request-ID
  • 504 Review, private language analyzer, or backend LLM processing exceeded its deadline.: application/json ErrorResponse Headers: Retry-After, X-Request-ID
GET/api/ai-code-review/v1/reviews/{reviewId}getReviewStatusRetrieve owner-scoped review lifecycle statusbearerAuthNoneheader:X-Request-ID, path:reviewId
  • 200 Safe lifecycle metadata for the requested review: application/json ReviewStatus Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 404 The review does not exist or is not owned by the caller: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
DELETE/api/ai-code-review/v1/reviews/{reviewId}cancelReviewCancel an owner-scoped queued or running reviewbearerAuthNoneheader:X-Request-ID, path:reviewId
  • 200 The review is cancelled or was already cancelled: application/json ReviewStatus Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 404 The review does not exist or is not owned by the caller: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 409 A non-cancelled terminal outcome won the lifecycle race: application/json ErrorResponse Headers: X-Request-ID
  • 503 Durable queue cleanup is temporarily unavailable and cancellation should be retried: application/json ErrorResponse Headers: X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
GET/api/ai-code-review/v1/reviews/{reviewId}/resultgetReviewResultRetrieve the structured result of a completed owner-scoped reviewbearerAuthNoneheader:X-Request-ID, path:reviewId
  • 200 Structured output for the requested completed review: application/json ReviewResult Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 404 The review does not exist or is not owned by the caller: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 409 The review has not completed: application/json ErrorResponse Headers: X-Request-ID
  • 410 The completed review result has passed its retention period: application/json ErrorResponse Headers: X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
GET/api/ai-code-review/v1/provider-profile-capabilitiesgetProviderProfileCapabilitiesDiscover provider-profile registration capabilitiesbearerAuthNoneheader:X-Request-ID
  • 200 The current non-secret registration capabilities: application/json ProviderProfileCapabilities Headers: Cache-Control, X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
  • 503 The registration key material is unavailable or unusable: application/json ErrorResponse Headers: X-Request-ID
POST/api/ai-code-review/v1/provider-profilescreateProviderProfileRegister a provider profile, delivering its credential oncebearerAuthapplication/json (required ProviderProfileRegistration)header:X-Request-ID
  • 201 The profile is active and may be named by reviews: application/json ProviderProfile Headers: X-Request-ID
  • 400 Malformed framing, malformed JSON, or duplicate properties within structural limits: application/json ErrorResponse Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 409 The caller already holds its deployment-configured maximum of active profiles (error code provider_profile_limit_exceeded) or of retained registration operations (error code provider_profile_registration_limit); revoke one first. A registration_id reused with a different request, or one whose retained tombstone forbids reuse, returns provider_profile_registration_conflict, and a replay naming an already revoked profile returns provider_profile_registration_revoked. The sealed envelope was not consumed.: application/json ErrorResponse Headers: X-Request-ID
  • 413 Request, repository, or diff exceeds a limit evaluated before duplicate detection: application/json ErrorResponse Headers: X-Request-ID
  • 415 The request content type or content encoding is not supported: application/json ErrorResponse Headers: X-Request-ID
  • 422 Depth, request fields, or Git references fail validation: application/json ErrorResponse Headers: X-Request-ID
  • 429 Per-client rate or concurrency limit, or asynchronous review backlog capacity, was exceeded: application/json ErrorResponse Headers: Retry-After, X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
  • 503 The APISIX credential provisioner is unavailable (error code provider_provisioner_unavailable). New managed creates require a durable, versioned idempotency client; an interface-only provisioner is refused before the credential envelope is opened or a capacity slot is reserved. A failure after a remote attempt is ambiguous: an identified create or rotation has reserved its durable operation, and a managed rotation may already have advanced the profile and queued its superseded route for removal. Reconcile by replaying the same registration_id, or the same rotation_id and expected_version, rather than starting a new logical operation. An attempted request without an identifier is reconciled by the server's own maintenance.: application/json ErrorResponse Headers: X-Request-ID
GET/api/ai-code-review/v1/provider-profileslistProviderProfilesList the caller's provider profilesbearerAuthNoneheader:X-Request-ID
  • 200 Non-secret metadata of the caller's newest profiles: application/json ProviderProfileCollection Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
GET/api/ai-code-review/v1/provider-profiles/{profileId}getProviderProfileRead one caller-owned provider profilebearerAuthNoneheader:X-Request-ID, path:profileId
  • 200 Non-secret metadata of the requested profile: application/json ProviderProfile Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 404 The profile does not exist or is not owned by the caller: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
DELETE/api/ai-code-review/v1/provider-profiles/{profileId}revokeProviderProfileRevoke one caller-owned provider profilebearerAuthNoneheader:X-Request-ID, path:profileId
  • 204 The profile is revoked Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 404 The profile does not exist or is not owned by the caller: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 409 Concurrent rotations kept superseding the version being revoked; the profile stays active and the request may be repeated.: application/json ErrorResponse Headers: X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
  • 503 The APISIX credential provisioner is unavailable (error code provider_provisioner_unavailable). New managed creates require a durable, versioned idempotency client; an interface-only provisioner is refused before the credential envelope is opened or a capacity slot is reserved. A failure after a remote attempt is ambiguous: an identified create or rotation has reserved its durable operation, and a managed rotation may already have advanced the profile and queued its superseded route for removal. Reconcile by replaying the same registration_id, or the same rotation_id and expected_version, rather than starting a new logical operation. An attempted request without an identifier is reconciled by the server's own maintenance.: application/json ErrorResponse Headers: X-Request-ID
POST/api/ai-code-review/v1/provider-profiles/{profileId}/rotaterotateProviderProfileReplace a profile's credential and advance its versionbearerAuthapplication/json (required ProviderProfileRotation)header:X-Request-ID, path:profileId
  • 200 The rotated profile: application/json ProviderProfile Headers: X-Request-ID
  • 400 Malformed framing, malformed JSON, or duplicate properties within structural limits: application/json ErrorResponse Headers: X-Request-ID
  • 401 Missing or invalid service authentication: application/json ErrorResponse Headers: WWW-Authenticate, X-Request-ID
  • 403 Authenticated caller is not allowed to perform this review: application/json ErrorResponse Headers: X-Request-ID
  • 404 The profile does not exist or is not owned by the caller: application/json ErrorResponse Headers: X-Request-ID
  • 405 The request method is not supported by this endpoint: application/json ErrorResponse Headers: Allow, X-Request-ID
  • 406 The requested response representation is not available: application/json ErrorResponse Headers: X-Request-ID
  • 409 The profile is revoked, a concurrent change won, or the supplied rotation_id and expected_version no longer match their reservation (error code provider_profile_registration_conflict). A caller at its retained-operation maximum receives provider_profile_registration_limit. The sealed envelope was not consumed.: application/json ErrorResponse Headers: X-Request-ID
  • 413 Request, repository, or diff exceeds a limit evaluated before duplicate detection: application/json ErrorResponse Headers: X-Request-ID
  • 415 The request content type or content encoding is not supported: application/json ErrorResponse Headers: X-Request-ID
  • 422 Depth, request fields, or Git references fail validation: application/json ErrorResponse Headers: X-Request-ID
  • 429 Per-client rate or concurrency limit, or asynchronous review backlog capacity, was exceeded: application/json ErrorResponse Headers: Retry-After, X-Request-ID
  • 500 Unexpected internal failure: application/json ErrorResponse Headers: X-Request-ID
  • 503 The APISIX credential provisioner is unavailable (error code provider_provisioner_unavailable). New managed creates require a durable, versioned idempotency client; an interface-only provisioner is refused before the credential envelope is opened or a capacity slot is reserved. A failure after a remote attempt is ambiguous: an identified create or rotation has reserved its durable operation, and a managed rotation may already have advanced the profile and queued its superseded route for removal. Reconcile by replaying the same registration_id, or the same rotation_id and expected_version, rather than starting a new logical operation. An attempted request without an identifier is reconciled by the server's own maintenance.: application/json ErrorResponse Headers: X-Request-ID

Components

Headers

AuthenticationChallenge
{
    "description": "Service-token authentication challenge",
    "schema": {
        "type": "string",
        "const": "Bearer realm=\"AI Code Review Server\""
    }
}
RequestId
{
    "description": "Server-accepted or server-generated request identifier",
    "schema": {
        "type": "string"
    }
}
RetryAfter
{
    "description": "Seconds before the client should retry request admission",
    "schema": {
        "type": "integer",
        "minimum": 1
    }
}

Parameters

RequestId
{
    "name": "X-Request-ID",
    "in": "header",
    "required": false,
    "description": "Optional caller correlation identifier. Values containing 1 to 128 characters from A-Z, a-z, 0-9, dot, underscore, colon, and hyphen are retained. Other values are replaced with a server-generated identifier.",
    "schema": {
        "type": "string"
    },
    "x-retained-value-schema": {
        "type": "string",
        "minLength": 1,
        "maxLength": 128,
        "pattern": "^[A-Za-z0-9._:-]+$"
    }
}
IdempotencyKey
{
    "name": "Idempotency-Key",
    "in": "header",
    "required": false,
    "description": "Opaque key for safely retrying one review submission",
    "schema": {
        "type": "string",
        "minLength": 16,
        "maxLength": 128,
        "pattern": "^[A-Za-z0-9._:-]+$"
    }
}
Prefer
{
    "name": "Prefer",
    "in": "header",
    "required": false,
    "description": "Set to respond-async to request asynchronous processing",
    "schema": {
        "type": "string",
        "enum": [
            "respond-async"
        ]
    }
}
ProfileId
{
    "name": "profileId",
    "in": "path",
    "required": true,
    "schema": {
        "type": "string",
        "format": "uuid"
    }
}

Responses

BadRequest
{
    "description": "Malformed framing, malformed JSON, or duplicate properties within structural limits",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
Unauthorized
{
    "description": "Missing or invalid service authentication",
    "headers": {
        "WWW-Authenticate": {
            "$ref": "#/components/headers/AuthenticationChallenge"
        },
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
Forbidden
{
    "description": "Authenticated caller is not allowed to perform this review",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
MethodNotAllowed
{
    "description": "The request method is not supported by this endpoint",
    "headers": {
        "Allow": {
            "description": "Methods supported by this endpoint",
            "schema": {
                "type": "string"
            }
        },
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
NotAcceptable
{
    "description": "The requested response representation is not available",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
Conflict
{
    "description": "Idempotency conflict or incompatible repository state",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
ContentTooLarge
{
    "description": "Request, repository, or diff exceeds a limit evaluated before duplicate detection",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
UnsupportedMediaType
{
    "description": "The request content type or content encoding is not supported",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
UnprocessableContent
{
    "description": "Depth, request fields, or Git references fail validation",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
TooManyRequests
{
    "description": "Per-client rate or concurrency limit, or asynchronous review backlog capacity, was exceeded",
    "headers": {
        "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
        },
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
InternalError
{
    "description": "Unexpected internal failure",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
BadGateway
{
    "description": "APISIX or an LLM provider returned an invalid response, or an enabled private language analyzer returned malformed output or failed its tool. No analyzer path, source, tool output, or private sidecar outcome is returned.",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
Unavailable
{
    "description": "Review service or a required dependency is unavailable, including an enabled language analyzer whose compatible sidecar is not ready. Disabled review submission uses the canonical service_unavailable code after authentication and route permission, without accepting work.",
    "headers": {
        "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
        },
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
ProviderProfileNotFound
{
    "description": "The profile does not exist or is not owned by the caller",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
ProvisionerUnavailable
{
    "description": "The APISIX credential provisioner is unavailable (error code provider_provisioner_unavailable). New managed creates require a durable, versioned idempotency client; an interface-only provisioner is refused before the credential envelope is opened or a capacity slot is reserved. A failure after a remote attempt is ambiguous: an identified create or rotation has reserved its durable operation, and a managed rotation may already have advanced the profile and queued its superseded route for removal. Reconcile by replaying the same registration_id, or the same rotation_id and expected_version, rather than starting a new logical operation. An attempted request without an identifier is reconciled by the server's own maintenance.",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
ProviderProfileRegistrationUnavailable
{
    "description": "The registration key material is unavailable or unusable",
    "headers": {
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}
GatewayTimeout
{
    "description": "Review, private language analyzer, or backend LLM processing exceeded its deadline.",
    "headers": {
        "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
        },
        "X-Request-ID": {
            "$ref": "#/components/headers/RequestId"
        }
    },
    "content": {
        "application/json": {
            "schema": {
                "$ref": "#/components/schemas/ErrorResponse"
            }
        }
    }
}

Security schemes

bearerAuth
{
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "<client-id>.<secret>",
    "description": "Deployment-owned client-to-server service token. This is not an APISIX or LLM provider credential. The lowercase client ID starts with an ASCII letter and then contains only letters, digits, underscores, or hyphens."
}

Schemas

HealthStatus
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "status"
    ],
    "properties": {
        "status": {
            "type": "string",
            "enum": [
                "ok",
                "ready",
                "not_ready"
            ]
        }
    }
}
ReviewRequest
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "repository_url",
        "branch",
        "base_commit_id",
        "commit_id",
        "provider_profile_id"
    ],
    "properties": {
        "repository_url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "pattern": "^[Hh][Tt][Tt][Pp][Ss]://(?:\\[[0-9A-Fa-f:.]+\\]|\\[[Vv][0-9A-Fa-f]+\\.[A-Za-z0-9._~!$&'()*+,;=:-]+\\]|(?:[A-Za-z0-9._~!$&'()*+,;=-]|%[0-9A-Fa-f]{2})+)(?::(?:[0-9]{1,4}|[0-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(?:/(?:[A-Za-z0-9._~!$&'()*+,;=:@-]|%[0-9A-Fa-f]{2})*)*(?:\\?(?:[A-Za-z0-9._~!$&'()*+,;=:@/?-]|%[0-9A-Fa-f]{2})*)?(?:#(?:[A-Za-z0-9._~!$&'()*+,;=:@/?-]|%[0-9A-Fa-f]{2})*)?(?![\\s\\S])",
            "description": "HTTPS URL with an optional port from 0 through 65535"
        },
        "branch": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "pattern": "^(?!HEAD(?![\\s\\S]))(?![-/])(?!\\.)(?![\\s\\S]*/\\.)(?![^/]*\\.lock(?:/|(?![\\s\\S])))(?![\\s\\S]*/[^/]*\\.lock(?:/|(?![\\s\\S])))(?![\\s\\S]*(?://|\\.\\.|@\\{|[\\x00-\\x20\\x7F~^:?*\\[\\\\]))(?![\\s\\S]*[/.](?![\\s\\S]))[\\s\\S]+$"
        },
        "base_commit_id": {
            "$ref": "#/components/schemas/CanonicalGitObjectId"
        },
        "commit_id": {
            "$ref": "#/components/schemas/CanonicalGitObjectId"
        },
        "output_language": {
            "type": "string",
            "minLength": 2,
            "maxLength": 35,
            "pattern": "^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*(?![\\s\\S])",
            "description": "Uses the deployment-configured default when omitted."
        },
        "review_policy": {
            "$ref": "#/components/schemas/ReviewPolicy"
        },
        "environments": {
            "description": "Caller-provided target environments rendered verbatim on one line in every chunk. Reject C0/C1 controls, TAB, CR, LF, NEL, U+2028, U+2029, bidi controls, Unicode tags, and consecutive variation selectors. No policy permission is required for environments alone.",
            "type": "array",
            "maxItems": 20,
            "uniqueItems": true,
            "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 120
            }
        },
        "provider_profile_id": {
            "$ref": "#/components/schemas/ProviderProfileId"
        }
    }
}
ReviewPolicy
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "format",
        "content"
    ],
    "description": "Optional caller criteria, never server instructions. Explicit null is invalid. Structural and fixed validation precede owner/key digest replay; new policy submissions then require submit ai code review policies permission (403 access_denied), followed by the operational byte cap (422). Accepted identical replays survive permission revocation and operational-cap reduction; changed criteria return 409.",
    "properties": {
        "format": {
            "type": "string",
            "enum": [
                "text/markdown",
                "text/plain"
            ]
        },
        "content": {
            "type": "string",
            "minLength": 1,
            "maxLength": 98307,
            "x-canonical-maximum-utf8-bytes": 49152,
            "x-default-submission-maximum-utf8-bytes": 32768,
            "description": "UTF-8 text. Convert CRLF and CR to LF and remove exactly one leading BOM before validation, hashing and storage; otherwise preserve bytes. Canonical content must be nonempty and at most 49152 UTF-8 bytes; new submissions default to a configurable 32768-byte cap. The larger wire maxLength accommodates CRLF and BOM before canonicalization; the independent HTTP JSON document ceiling is 1048576 bytes. Reject C0/C1 controls except TAB/LF, bidi controls, Unicode tags, and consecutive variation selectors. Include the full canonical document in every chunk. Source criteria from trusted base/config independent of the reviewed head; the server cannot prove provenance."
        }
    }
}
ReviewPolicyReceipt
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "format",
        "sha256",
        "bytes"
    ],
    "description": "Present if and only if the submission contained review_policy, including accepted replay after terminal input purge. Confirms canonical receipt, not model compliance. Absent for no-policy and environments-only requests.",
    "properties": {
        "format": {
            "type": "string",
            "enum": [
                "text/markdown",
                "text/plain"
            ]
        },
        "sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
        },
        "bytes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 49152
        }
    }
}
ProviderProfileId
{
    "type": "string",
    "format": "uuid",
    "minLength": 36,
    "maxLength": 36,
    "pattern": "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}(?![\\s\\S])",
    "description": "Identifier of a provider profile registered by the calling client. For a new submission, an unknown, revoked, or foreign identifier is rejected with one identical validation error before repository checkout, queue allocation, or LLM request. An identical accepted owner/key replay returns its original review even after profile rotation or revocation; changed canonical input under that key conflicts. The accepted version is pinned to the review: a profile rotated or revoked before the worker runs fails that review with provider_profile_unavailable instead of executing with inputs the caller never saw."
}
ProviderProfileRegistration
{
    "type": "object",
    "additionalProperties": false,
    "description": "The create request body. It alone accepts registration_id; the rotate endpoint rejects that member as unknown and accepts rotation_id with expected_version instead.",
    "required": [
        "provider",
        "model",
        "execution_route",
        "sealed_credential"
    ],
    "properties": {
        "provider": {
            "type": "string",
            "enum": [
                "openai",
                "azure_openai",
                "anthropic"
            ],
            "description": "Server allow-listed provider adapter. Only openai has a reviewed adapter today; the others are refused at registration."
        },
        "model": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "Provider model identifier, validated by the adapter."
        },
        "execution_route": {
            "type": "string",
            "enum": [
                "apisix_managed",
                "direct_server"
            ]
        },
        "sealed_credential": {
            "type": "string",
            "writeOnly": true,
            "minLength": 1,
            "maxLength": 8192,
            "pattern": "^[A-Za-z0-9_-]+(?![\\s\\S])",
            "description": "One-time base64url envelope: a JSON object with members v (1), kid (registration key identifier), and sealed (a libsodium sealed box, base64url) whose plaintext is a JSON object with members client_id (the caller's service-token client ID), issued_at (Unix seconds), nonce (base64url, 16-64 bytes), and credential (the provider API key). It is never returned, logged, or retained; a replayed nonce is refused."
        },
        "registration_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![\\s\\S])",
            "description": "Optional, non-secret lowercase canonical UUID generated once by the client for one logical create. Supplying it makes a retry of that create converge on one profile identifier, one stored credential, and one APISIX route; the completed replay returns the existing profile with 201 without opening the newly supplied envelope. Reusing it with a different provider, model, or route returns provider_profile_registration_conflict, and a replay after revocation returns provider_profile_registration_revoked. A create without this member remains accepted and is treated as a new logical create."
        }
    }
}
ProviderProfileRotation
{
    "type": "object",
    "additionalProperties": false,
    "description": "The rotate request body. It carries the same four registration members and, unlike create, accepts rotation_id and expected_version. The create member registration_id is rejected here as unknown before the sealed envelope is opened.",
    "required": [
        "provider",
        "model",
        "execution_route",
        "sealed_credential"
    ],
    "properties": {
        "provider": {
            "$ref": "#/components/schemas/ProviderProfileRegistration/properties/provider"
        },
        "model": {
            "$ref": "#/components/schemas/ProviderProfileRegistration/properties/model"
        },
        "execution_route": {
            "$ref": "#/components/schemas/ProviderProfileRegistration/properties/execution_route"
        },
        "sealed_credential": {
            "$ref": "#/components/schemas/ProviderProfileRegistration/properties/sealed_credential"
        },
        "rotation_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![\\s\\S])",
            "description": "Optional, non-secret lowercase canonical UUID identifying one logical rotation. It must be sent together with expected_version; one member alone is rejected with 422. A retry that repeats both reuses the reserved target version, so a managed rotation cannot materialize two routes."
        },
        "expected_version": {
            "type": "integer",
            "minimum": 1,
            "description": "The active profile version the client rotated from. It must be sent together with rotation_id. A value that does not match the active version returns provider_profile_registration_conflict before the sealed envelope is opened."
        }
    }
}
ProviderProfile
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "id",
        "provider",
        "model",
        "execution_route",
        "status",
        "version",
        "created_at",
        "updated_at"
    ],
    "properties": {
        "id": {
            "$ref": "#/components/schemas/ProviderProfileId"
        },
        "provider": {
            "type": "string"
        },
        "model": {
            "type": "string"
        },
        "execution_route": {
            "type": "string",
            "enum": [
                "apisix_managed",
                "direct_server"
            ]
        },
        "status": {
            "type": "string",
            "enum": [
                "active",
                "revoked"
            ]
        },
        "version": {
            "type": "integer",
            "minimum": 1
        },
        "created_at": {
            "type": "string",
            "format": "date-time"
        },
        "updated_at": {
            "type": "string",
            "format": "date-time"
        }
    }
}
ProviderProfileCollection
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "profiles"
    ],
    "properties": {
        "profiles": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/ProviderProfile"
            }
        }
    }
}
ProviderProfileCapabilities
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "registration",
        "providers"
    ],
    "properties": {
        "registration": {
            "$ref": "#/components/schemas/ProviderProfileRegistrationCapabilities"
        },
        "providers": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/ProviderProfileCapability"
            }
        }
    }
}
ProviderProfileRegistrationCapabilities
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "envelope_version",
        "algorithm",
        "key_id",
        "public_key",
        "maximum_envelope_age_seconds"
    ],
    "properties": {
        "envelope_version": {
            "type": "integer",
            "const": 1
        },
        "algorithm": {
            "type": "string",
            "const": "sodium_crypto_box_seal"
        },
        "key_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}(?![\\s\\S])"
        },
        "public_key": {
            "type": "string",
            "minLength": 43,
            "maxLength": 43,
            "pattern": "^[A-Za-z0-9_-]{43}(?![\\s\\S])",
            "description": "Exactly 32 raw public-key bytes in unpadded base64url."
        },
        "maximum_envelope_age_seconds": {
            "type": "integer",
            "minimum": 1
        }
    }
}
ProviderProfileCapability
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "id",
        "execution_routes"
    ],
    "properties": {
        "id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[a-z][a-z0-9_]*(?![\\s\\S])"
        },
        "execution_routes": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
                "type": "string",
                "enum": [
                    "apisix_managed",
                    "direct_server"
                ]
            }
        }
    }
}
CanonicalGitObjectId
{
    "type": "string",
    "description": "Strict full SHA-1 or SHA-256 Git object identifier",
    "pattern": "^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})(?![\\s\\S])"
}
ReviewJob
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "review_id",
        "result_url",
        "status",
        "status_url",
        "submitted_at"
    ],
    "properties": {
        "review_policy": {
            "$ref": "#/components/schemas/ReviewPolicyReceipt"
        },
        "review_id": {
            "type": "string",
            "format": "uuid"
        },
        "status": {
            "type": "string",
            "description": "Fixed v1 asynchronous-submission acceptance state.",
            "const": "queued"
        },
        "status_url": {
            "type": "string",
            "format": "uri-reference"
        },
        "result_url": {
            "type": "string",
            "format": "uri-reference"
        },
        "submitted_at": {
            "type": "string",
            "format": "date-time"
        },
        "expires_at": {
            "type": "string",
            "format": "date-time"
        }
    }
}
ReviewResult
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "review_id",
        "status",
        "findings",
        "summary",
        "rendered_result",
        "completed_at"
    ],
    "properties": {
        "review_id": {
            "type": "string",
            "format": "uuid"
        },
        "status": {
            "type": "string",
            "const": "completed"
        },
        "findings": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/Finding"
            }
        },
        "summary": {
            "$ref": "#/components/schemas/ReviewSummary"
        },
        "rendered_result": {
            "type": "string",
            "description": "Bounded plain-text report with Summary and Detail and dynamically sized backtick code fences; no ANSI escapes or HTML rendering"
        },
        "completed_at": {
            "type": "string",
            "format": "date-time"
        }
    }
}
ReviewStatus
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "attempt",
        "created_at",
        "error_code",
        "expires_at",
        "finished_at",
        "review_id",
        "started_at",
        "status"
    ],
    "properties": {
        "attempt": {
            "type": "integer",
            "minimum": 0
        },
        "created_at": {
            "type": "string",
            "format": "date-time"
        },
        "error_code": {
            "type": [
                "string",
                "null"
            ]
        },
        "expires_at": {
            "type": [
                "string",
                "null"
            ],
            "format": "date-time"
        },
        "finished_at": {
            "type": [
                "string",
                "null"
            ],
            "format": "date-time"
        },
        "review_id": {
            "type": "string",
            "format": "uuid"
        },
        "started_at": {
            "type": [
                "string",
                "null"
            ],
            "format": "date-time"
        },
        "status": {
            "type": "string",
            "enum": [
                "cancelled",
                "completed",
                "expired",
                "failed",
                "queued",
                "running"
            ]
        }
    }
}
Finding
{
    "type": "object",
    "additionalProperties": false,
    "description": "Actionable LLM feedback only; analyzer records remain review context and are not returned as findings",
    "required": [
        "finding_id",
        "severity",
        "category",
        "message",
        "path",
        "line",
        "suggestion",
        "suggestion_format"
    ],
    "properties": {
        "finding_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
        },
        "severity": {
            "type": "string",
            "enum": [
                "critical",
                "high",
                "medium",
                "low",
                "info"
            ]
        },
        "category": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
        },
        "message": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4000
        },
        "path": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1024
        },
        "line": {
            "type": "integer",
            "minimum": 1
        },
        "end_line": {
            "type": [
                "integer",
                "null"
            ],
            "minimum": 1
        },
        "function": {
            "type": [
                "string",
                "null"
            ],
            "minLength": 1,
            "maxLength": 256,
            "description": "Named function or method supported by supplied context; null when unavailable"
        },
        "suggestion": {
            "type": "string",
            "minLength": 1,
            "maxLength": 8000,
            "description": "Nonblank concrete corrected code or unified diff; never applied automatically"
        },
        "suggestion_format": {
            "type": "string",
            "enum": [
                "code",
                "unified_diff"
            ]
        }
    }
}
ReviewSummary
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "files_reviewed",
        "finding_count"
    ],
    "properties": {
        "files_reviewed": {
            "type": "integer",
            "minimum": 0
        },
        "finding_count": {
            "type": "integer",
            "minimum": 0
        },
        "truncated": {
            "type": "boolean",
            "default": false,
            "description": "True when review material, findings, or rendered report bytes were omitted"
        }
    }
}
ErrorResponse
{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "error"
    ],
    "properties": {
        "error": {
            "type": "object",
            "additionalProperties": false,
            "required": [
                "code",
                "message",
                "request_id"
            ],
            "properties": {
                "code": {
                    "type": "string",
                    "pattern": "^[a-z][a-z0-9_]*$"
                },
                "message": {
                    "type": "string",
                    "description": "Localized human-readable message; clients must use code for program logic. An oversized translation falls back to the bounded English source message.",
                    "minLength": 1,
                    "maxLength": 1000
                },
                "request_id": {
                    "type": "string"
                },
                "details": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                            "path",
                            "code",
                            "message"
                        ],
                        "properties": {
                            "path": {
                                "type": "string",
                                "description": "JSON Pointer to the invalid request value"
                            },
                            "code": {
                                "type": "string"
                            },
                            "message": {
                                "type": "string",
                                "description": "Localized human-readable validation message"
                            }
                        }
                    }
                }
            }
        }
    }
}