> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Establece o rota una credencial de cola

> Establece o rota la credencial de salida para una suscripción de cola (`sqs`, `rabbitmq`, `eventbridge`) con probe-on-write: la credencial candidata se mantiene en memoria, se prueba (conexión + auth) de inmediato y se persiste cifrada solo ante el éxito de la sonda — una sonda fallida no almacena nada. Una sonda exitosa pasa la suscripción de `pending_verification` a `active`. La credencial es de solo escritura: se suministra únicamente aquí y nunca se devuelve, ni siquiera enmascarada, en ningún camino de lectura. Un fallo de sonda clasificado sigue siendo un `200`. Esta ruta es naturalmente idempotente y no requiere header `X-Idempotency`.



## OpenAPI

````yaml es/openapi/v3-current/streaming-hub.yaml put /v1/subscriptions/{id}/credential
openapi: 3.1.0
info:
  title: Lerian Streaming Hub API
  version: v1.0.0
  contact:
    email: contact@lerian.studio
    name: Lerian Studio
    url: https://lerian.studio
  license:
    name: Lerian Studio General License
  description: >-
    La API de control-plane de Streaming Hub. Streaming Hub es el borde
    gestionado de entrega de eventos de Lerian: consume CloudEvents del backbone
    de streaming interno de la plataforma y los distribuye a los destinos
    externos propios de cada tenant — webhooks, Amazon SQS, RabbitMQ, Amazon
    EventBridge o una bandeja de entrada de tipo pull. Esta API permite a un
    tenant explorar el catálogo de eventos alimentado por el manifest, crear y
    gestionar suscripciones de entrega, verificar y rotar sus credenciales, leer
    la salud de entrega y hacer pull de los eventos a los que tiene derecho.


    Los errores usan un envelope plano `{"error":"<token>"}` (un token de baja
    cardinalidad y legible por máquina — nunca RFC 9457 problem+json). Las
    operaciones de mutación requieren un header `X-Idempotency` para semántica
    at-most-once; una petición reproducida (replay) devuelve la respuesta
    original byte a byte con `X-Idempotency-Replayed: true`. El catálogo y la
    superficie de eventos pull están acotados por tenant a través del JWT
    bearer; los endpoints operacionales de sonda (`/healthz`, `/readyz`,
    `/version`, `/runtime`, `/metrics`) no requieren autenticación. Streaming
    Hub es de código cerrado bajo la Lerian Studio General License.
servers:
  - url: https://streaming-hub.sandbox.lerian.net
security:
  - BearerAuth: []
tags:
  - name: Catalog
    description: >-
      Explora el catálogo de tipos de evento disponibles para suscripción,
      alimentado por el manifest.
  - name: Subscriptions
    description: >-
      Crea, lee, actualiza y elimina suscripciones de entrega, y gestiona el
      ciclo de vida de verificación del destino (ping, verify, credential,
      delegated grant, rotación de secreto, health).
  - name: Event Delivery
    description: >-
      Haz pull de los eventos a los que tienes derecho para una suscripción de
      tipo pull (lectura cursor-as-acknowledgment).
  - name: Admin
    description: >-
      Análisis forense de operador entre tenants. Requiere un scope de
      autorización de operador.
  - name: Operational
    description: >-
      Sondas de liveness, readiness, build, runtime y métricas sin
      autenticación.
paths:
  /v1/subscriptions/{id}/credential:
    put:
      tags:
        - Subscriptions
      summary: Establece o rota una credencial de cola
      description: >-
        Establece o rota la credencial de salida para una suscripción de cola
        (`sqs`, `rabbitmq`, `eventbridge`) con probe-on-write: la credencial
        candidata se mantiene en memoria, se prueba (conexión + auth) de
        inmediato y se persiste cifrada solo ante el éxito de la sonda — una
        sonda fallida no almacena nada. Una sonda exitosa pasa la suscripción de
        `pending_verification` a `active`. La credencial es de solo escritura:
        se suministra únicamente aquí y nunca se devuelve, ni siquiera
        enmascarada, en ningún camino de lectura. Un fallo de sonda clasificado
        sigue siendo un `200`. Esta ruta es naturalmente idempotente y no
        requiere header `X-Idempotency`.
      operationId: putSubscriptionCredential
      parameters:
        - $ref: '#/components/parameters/SubscriptionId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CredentialRequest'
      responses:
        '200':
          description: >-
            La sonda se ejecutó; el cuerpo lleva el resultado clasificado. En
            caso de éxito la credencial se persistió y la suscripción está
            `active`; en un fallo clasificado no se persistió nada.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProbeResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: >-
            La petición es corregible por el llamador. `error` es
            `validation_error` (un `sinkConfig` ausente o vacío) o
            `endpoint_blocked` (el host del broker resolvió a una dirección
            bloqueada, privada o de metadatos).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - BearerAuth: []
components:
  parameters:
    SubscriptionId:
      name: id
      in: path
      required: true
      description: The unique identifier of the subscription (UUIDv7).
      schema:
        type: string
        format: uuid
  schemas:
    CredentialRequest:
      type: object
      additionalProperties: false
      description: >-
        The queue-credential body. `sinkConfig` is a kind-specific, write-only
        object that is probed and, on success, stored encrypted. It is never
        returned on any read path.
      properties:
        sinkConfig:
          type: object
          additionalProperties: true
          description: >-
            The candidate outbound credential for the queue kind. For
            `rabbitmq`, an object such as
            `{"uri":"amqps://user:pass@broker.example.com:5671/vhost"}`; for AWS
            kinds, the region and access material. Write-only — never logged or
            returned.
          examples:
            - uri: amqps://user:pass@broker.example.com:5671/vhost
      required:
        - sinkConfig
    ProbeResult:
      type: object
      additionalProperties: false
      description: >-
        The classified result of a synchronous probe (ping, verify, or
        credential write). A classified failure is still returned with HTTP
        `200` — the probe ran and produced a verdict. It carries no secret,
        endpoint, or detail string.
      properties:
        outcome:
          $ref: '#/components/schemas/Outcome'
        statusCode:
          type: integer
          description: >-
            The target's protocol status. For webhook probes, the HTTP status
            (`0` when none applies, e.g. a transport error or a blocked
            endpoint). For queue-kind credential probes, always `0`.
          examples:
            - 200
        errorClass:
          type: string
          description: A frozen taxonomy token classifying a failure. Empty on success.
          examples:
            - ''
      required:
        - outcome
        - statusCode
        - errorClass
    Error:
      type: object
      additionalProperties: false
      description: >-
        The flat error envelope used across the `/v1` and `/admin` surfaces. It
        carries a single low-cardinality, machine-readable token and never leaks
        secret material or internal detail. (A `403` from the authorization
        decision point is the one exception — its body is plain text.)
      properties:
        error:
          type: string
          description: The machine-readable error token.
          examples:
            - not_found
      required:
        - error
    Outcome:
      type: string
      description: The classified verdict of a synchronous probe.
      enum:
        - ok
        - failed
  responses:
    BadRequest:
      description: El cuerpo de la petición está malformado — `error` es `bad_request`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: >-
        La autenticación falló, o no hay contexto de tenant confiable. `error`
        es `unauthorized` (cuerpo uniforme — no se revela ninguna razón).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >-
        El punto de decisión de autorización denegó la petición. El cuerpo es
        texto plano (no el envelope de error JSON).
      content:
        text/plain:
          schema:
            type: string
    NotFound:
      description: >-
        El recurso está ausente, soft-deleted o pertenece a otro tenant — un
        `error` uniforme de `not_found` (sin oráculo de existencia).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: >-
        Un fallo de infraestructura. `error` es `internal_error` (sanitizado; el
        detalle se registra, nunca se devuelve).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Un JWT bearer emitido por plugin-auth (lib-auth). La identidad del
        tenant se resuelve a partir de los claims validados del token; la
        superficie `/v1` nunca lee un tenant del cuerpo, del path ni de la
        query. Los llamadores de máquina obtienen un token vía el flujo
        client-credentials de plugin-auth. La superficie `/admin` autoriza
        contra un scope de operador y no lleva contexto de tenant.

````