openapi: 3.1.0
info:
  title: Constal Credential API
  version: 1.0.0
  description: CredentialProvider discovery and setup, Credential creation, authorization, lifecycle, and inspection.
servers:
  - url: https://platform.constal.ai
security:
  - bearerAuth: []
paths:
  /v1/namespaces/{namespace}/credential-provider-catalog:
    get:
      operationId: listCredentialProviderCatalog
      summary: List CredentialProvider packages visible to the authenticated tenant.
      parameters:
        - $ref: '#/components/parameters/Namespace'
      responses:
        '200': { description: Provider package catalog }
  /v1/namespaces/{namespace}/credential-providers:
    get:
      operationId: listCredentialProviders
      summary: List installed CredentialProvider Resources.
      parameters:
        - $ref: '#/components/parameters/Namespace'
      responses:
        '200': { description: Installed providers }
  /v1/namespaces/{namespace}/credential-providers/install:
    post:
      operationId: installCredentialProvider
      summary: Install one immutable provider package instance.
      parameters:
        - $ref: '#/components/parameters/Namespace'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProviderInstall'
      responses:
        '201': { description: Provider installed }
        '400': { $ref: '#/components/responses/Invalid' }
        '403': { $ref: '#/components/responses/Denied' }
  /v1/namespaces/{namespace}/credentials:
    get:
      operationId: listCredentials
      summary: List Credential Resources.
      parameters:
        - $ref: '#/components/parameters/Namespace'
      responses:
        '200': { description: Credential list without secret material }
    post:
      operationId: createCredential
      summary: Import, mint, or begin authorization for one Credential.
      parameters:
        - $ref: '#/components/parameters/Namespace'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialCreate'
      responses:
        '200': { description: Imported or synchronously minted Credential }
        '202': { description: Authorization or mint is pending }
        '400': { $ref: '#/components/responses/Invalid' }
        '422': { description: Provider or producer unavailable }
  /v1/namespaces/{namespace}/credentials/{credential}:
    get:
      operationId: getCredentialMetadata
      summary: Read authoritative Credential metadata and version state.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Credential metadata without material }
  /v1/namespaces/{namespace}/credentials/{credential}/versions:
    post:
      operationId: addCredentialVersion
      summary: Add imported material as a scheduled version.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Version stored }
  /v1/namespaces/{namespace}/credentials/{credential}/activate:
    post:
      operationId: activateCredentialVersion
      summary: Activate one scheduled version.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Version activated }
  /v1/namespaces/{namespace}/credentials/{credential}/rotate:
    post:
      operationId: rotateCredential
      summary: Ask the pinned provider to mint and verify replacement material.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Rotation completed }
        '202': { description: Rotation pending }
  /v1/namespaces/{namespace}/credentials/{credential}/authorize:
    post:
      operationId: authorizeCredential
      summary: Begin or continue interactive Credential authorization.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '202': { description: Authorization URL issued or completion pending }
  /v1/namespaces/{namespace}/credentials/{credential}/revoke:
    post:
      operationId: revokeCredential
      summary: Permanently revoke one version or all usable versions.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Revocation recorded }
  /v1/namespaces/{namespace}/credentials/{credential}/consumers:
    get:
      operationId: listCredentialConsumers
      summary: List current Resource consumers.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Consumer references }
  /v1/namespaces/{namespace}/credentials/{credential}/uses:
    get:
      operationId: listCredentialUses
      summary: List bounded recent use records.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Use records }
  /v1/namespaces/{namespace}/credentials/{credential}/events:
    get:
      operationId: listCredentialEvents
      summary: List bounded lifecycle events.
      parameters:
        - $ref: '#/components/parameters/Namespace'
        - $ref: '#/components/parameters/Credential'
      responses:
        '200': { description: Lifecycle events }
  /v1/credential-authorizations/callback:
    get:
      operationId: completeCredentialAuthorization
      summary: Complete a provider browser authorization using signed state.
      security: []
      parameters:
        - name: state
          in: query
          required: true
          schema: { type: string, maxLength: 4096 }
        - name: code
          in: query
          required: false
          schema: { type: string, maxLength: 4096 }
      responses:
        '303': { description: Redirect to the Console Credential page }
        '400': { description: Invalid or expired authorization state }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
  parameters:
    Namespace:
      name: namespace
      in: path
      required: true
      schema: { type: string, pattern: '^[a-z0-9][a-z0-9._-]{0,127}$' }
    Credential:
      name: credential
      in: path
      required: true
      schema: { type: string, pattern: '^[a-z0-9][a-z0-9-]{0,62}$' }
  schemas:
    CredentialCreate:
      type: object
      required: [id, provider, configuration]
      properties:
        id: { type: string, pattern: '^[a-z0-9][a-z0-9-]{0,62}$' }
        provider: { type: string, description: Installed CredentialProvider CRN }
        configuration: { type: object, description: Non-secret provider-owned parameters }
        material: { type: string, minLength: 1, writeOnly: true }
        policies: { type: array, items: { type: string } }
    ProviderInstall:
      type: object
      required: [package, id, config, policies]
      properties:
        package: { type: object, description: Immutable catalog package reference }
        id: { type: string, pattern: '^[a-z0-9][a-z0-9-]{0,62}$' }
        config: { type: object, description: Non-secret provider instance configuration }
        credentials: { type: object, additionalProperties: { type: string } }
        bootstrap: { type: object, description: Existing references or one-time inline setup secrets }
        setupId: { type: string, format: uuid }
        policies: { type: array, items: { type: string } }
  responses:
    Invalid:
      description: Request does not satisfy the provider or platform contract.
    Denied:
      description: Authenticated Policy denied the operation.
