openapi: 3.0.3
info:
  title: API de Registry admitida para Docker Hub
  description: |
    Docker Hub es un registry compatible con OCI, lo que significa que cumple con los estándares abiertos
    definidos por la Open Container Initiative (OCI) para la distribución de imágenes de contenedor.
    Esto asegura la compatibilidad con una amplia gama de herramientas y plataformas en el ecosistema de contenedores.

    Esta referencia documenta el subconjunto de la API HTTP de Registry V2 admitido por Docker Hub.
    Se centra en la obtención (pull), envío (push) y eliminación de imágenes. No cubre la especificación completa de OCI Distribution Specification.

    Para ver la especificación completa de OCI, consulta [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec).
servers:
  - description: Docker Hub registry API
    x-audience: public
    url: https://registry-1.docker.io

tags:
  - name: overview
    x-displayName: Descripción general
    description: |
      Todos los endpoints de esta API están prefijados por la versión y el nombre del repositorio, por ejemplo:

      ```
      /v2/<name>/
      ```

      Este formato proporciona control de acceso estructurado y delimitación basada en URI para las operaciones de imágenes.

      Por ejemplo, para interactuar con el repositorio `library/ubuntu`, usa:

      ```
      /v2/library/ubuntu/
      ```

      Los nombres de repositorio deben cumplir con estos requisitos:
      1. Consistir en componentes de ruta que coincidan con `[a-z0-9]+(?:[._-][a-z0-9]+)*`
      2. Si hay más de un componente, deben estar separados por `/`
      3. El nombre completo del repositorio debe tener menos de 256 caracteres


  - name: authentication
    x-displayName: Autenticación
    description: |
      Especifica la autenticación de registry.
    externalDocs:
      description: Flujo de trabajo detallado de autenticación y uso de tokens
      url: https://docs-docker.esdocu.com/reference/api/registry/auth/

  - name: Manifests
    x-displayName: Manifiestos
    description: |
      Los manifiestos de imagen son documentos JSON que describen una imagen: su blob de configuración, los digests de cada blob de capa y metadatos como tipos de medio (media-types) y anotaciones.

  - name: Blobs
    x-displayName: Blobs
    description: |
      Los blobs son los objetos binarios referenciados desde los manifiestos: el JSON de configuración y uno o más archivos tarball de capa comprimidos.

  - name: pull
    x-displayName: Obtención de imágenes (Pulling)
    description: |
      Obtener (pull) una imagen implica recuperar el manifiesto y descargar cada uno de los blobs de capa de la imagen. Esta sección describe los pasos generales seguidos por un ejemplo práctico.

      1. [Obtener un token bearer para el repositorio](https://docs-docker.esdocu.com/reference/api/registry/auth/).
      2. [Obtener el manifiesto de la imagen](#operation/GetImageManifest).
      3. Si la respuesta en el paso anterior es una lista de manifiestos de múltiples arquitecturas, debes hacer lo siguiente:
         - Analizar el arreglo `manifests[]` para ubicar el digest de tu plataforma de destino (por ejemplo, `linux/amd64`).
         - [Obtener el manifiesto de la imagen](#operation/GetImageManifest) utilizando el digest localizado.
      4. [Comprobar si el blob existe](#operation/CheckBlobExists) antes de descargarlo. El cliente debe enviar una solicitud `HEAD` para cada digest de capa.
      5. [Descargar cada blob de capa](#operation/GetBlob) utilizando el digest obtenido del manifiesto. El cliente debe enviar una solicitud `GET` para cada digest de capa.

      El siguiente ejemplo de script en bash obtiene `library/ubuntu:latest` de Docker Hub.

      ```bash
      #!/bin/bash

      # Paso 1: Obtener un token bearer
      TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull" | jq -r .token)
  
      # Paso 2: Obtener el manifiesto de la imagen. En este ejemplo, se devuelve una lista de manifiestos de imagen.
      curl -s -H "Authorization: Bearer $TOKEN" \
           -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \
           https://registry-1.docker.io/v2/library/ubuntu/manifests/latest \
           -o manifest-list.json
  
      # Paso 3a: Analizar el arreglo `manifests[]` para localizar el digest de tu plataforma de destino (por ejemplo, `linux/amd64`).
      IMAGE_MANIFEST_DIGEST=$(jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest' manifest-list.json)
  
      # Paso 3b: Obtener el manifiesto de la imagen específico de la plataforma
      curl -s -H "Authorization: Bearer $TOKEN" \
           -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
           https://registry-1.docker.io/v2/library/ubuntu/manifests/$IMAGE_MANIFEST_DIGEST \
           -o manifest.json
  
      # Paso 4: Enviar una solicitud HEAD para comprobar si existe el blob de capa
      DIGEST=$(jq -r '.layers[0].digest' manifest.json)
      curl -I -H "Authorization: Bearer $TOKEN" \
           https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST
  
      # Paso 5: Descargar el blob de capa
      curl -L -H "Authorization: Bearer $TOKEN" \
           https://registry-1.docker.io/v2/library/ubuntu/blobs/$DIGEST
      ```
    
      Este ejemplo obtiene el manifiesto y la primera capa para la imagen `ubuntu:latest` en la plataforma `linux/amd64`. Repite los pasos 4 y 5 para cada digest en el arreglo `.layers[]` en el manifiesto.


  - name: push
    x-displayName: Envío de imágenes (Pushing)
    description: |
      Enviar (push) una imagen implica subir los blobs de la imagen (como la configuración o las capas) y luego subir el manifiesto que hace referencia a esos blobs.
  
      Esta sección describe los pasos básicos para enviar una imagen utilizando la API de registry.
  
      1. [Obtener un token bearer para el repositorio](https://docs-docker.esdocu.com/reference/api/registry/auth/)
  
      2. [Comprobar si el blob existe](#operation/CheckBlobExists) utilizando una solicitud `HEAD` para cada digest de blob.
  
      3. Si el blob no existe, [subir el blob](#operation/CompleteBlobUpload) utilizando una solicitud `PUT` monolítica:
          - Primero, [iniciar la subida](#operation/InitiateBlobUpload) con `POST`.
          - Luego [subir y completar](#operation/CompleteBlobUpload) con `PUT`.

          **Nota**:  Alternativamente, puedes subir el blob en múltiples fragmentos (chunks) utilizando solicitudes `PATCH` para enviar cada fragmento, seguido de una solicitud `PUT` final para completar la subida. Esto se conoce como subida fragmentada (chunked upload) y es útil para blobs grandes o al reanudar subidas interrumpidas.

  
      4. [Subir el manifiesto de la imagen](#operation/PutImageManifest) utilizando una solicitud `PUT` para asociar la configuración y las capas.
  
      El siguiente ejemplo de script en bash envía un blob de configuración simulado (dummy) y un manifiesto a `yourusername/helloworld:latest` en Docker Hub. Puedes reemplazar `yourusername` con tu nombre de usuario de Docker Hub y `dckr_pat` con tu token de acceso personal de Docker Hub.
  
      ```bash
      #!/bin/bash
  
      USERNAME=yourusername
      PASSWORD=dckr_pat
      REPO=yourusername/helloworld
      TAG=latest
      CONFIG=config.json
      MIME_TYPE=application/vnd.docker.container.image.v1+json
  
      # Paso 1: Get a bearer token
      TOKEN=$(curl -s -u "$USERNAME:$PASSWORD" \
      "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:push,pull" \
      | jq -r .token)
  
      # Create a dummy config blob and compute its digest
      echo '{"architecture":"amd64","os":"linux","config":{},"rootfs":{"type":"layers","diff_ids":[]}}' > $CONFIG
      DIGEST="sha256:$(sha256sum $CONFIG | awk '{print $1}')"
  
      # Step 2: Check if the blob exists
      STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I \
        -H "Authorization: Bearer $TOKEN" \
        https://registry-1.docker.io/v2/$REPO/blobs/$DIGEST)
  
      if [ "$STATUS" != "200" ]; then
        # Step 3: Upload blob using monolithic upload
        LOCATION=$(curl -sI -X POST \
          -H "Authorization: Bearer $TOKEN" \
          https://registry-1.docker.io/v2/$REPO/blobs/uploads/ \
          | grep -i Location | tr -d '\r' | awk '{print $2}')
  
        curl -s -X PUT "$LOCATION&digest=$DIGEST" \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/octet-stream" \
          --data-binary @$CONFIG
      fi
  
      # Step 4: Upload the manifest that references the config blob
      MANIFEST=$(cat <<EOF
      {
        "schemaVersion": 2,
        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
        "config": {
          "mediaType": "$MIME_TYPE",
          "size": $(stat -c%s $CONFIG),
          "digest": "$DIGEST"
        },
        "layers": []
      }
      EOF
      )

      curl -s -X PUT \
        -H "Authorization: Bearer $TOKEN" \
        -H "Content-Type: application/vnd.docker.distribution.manifest.v2+json" \
        -d "$MANIFEST" \
        https://registry-1.docker.io/v2/$REPO/manifests/$TAG
  
      echo "Pushed image to $REPO:$TAG"
      ```

      Este ejemplo envía una imagen mínima sin capas. Para enviar una imagen completa, repite los pasos 2–3 para cada capa e incluye los digests de las capas en el campo `layers[]` del manifiesto.

  - name: delete
    x-displayName: Eliminación de imágenes (Deleting)
    description: |
      Eliminar una imagen implica eliminar su manifiesto por digest. Primero debes obtener el digest del manifiesto y luego emitir una solicitud `DELETE` utilizando ese digest.

      Solo se pueden eliminar manifiestos sin etiqueta (o aquellos que no están referenciados por otras etiquetas o imágenes). Si un manifiesto todavía está referenciado, el registry devuelve `403 Forbidden`.

      > **Nota**
      >
      > Las operaciones de eliminación de manifiestos pueden experimentar latencia y podrían devolver un error `500 Internal Server Error` durante la eliminación. El sistema reintenta automáticamente la eliminación en segundo plano, por lo que el manifiesto eventualmente se eliminará. No es necesario que reintentes manualmente la solicitud.

      Esta sección describe los pasos básicos para eliminar una imagen utilizando la API de registry.

      1. [Obtener un token bearer para el repositorio](https://docs-docker.esdocu.com/reference/api/registry/auth/).
      2. [Obtener el manifiesto](#operation/GetImageManifest) utilizando la etiqueta de la imagen.
      3. Obtener la cabecera `Docker-Content-Digest` de la respuesta del manifiesto. Este digest identifica de forma única el manifiesto.
      4. [Eliminar el manifiesto](#operation/DeleteImageManifest) utilizando una solicitud `DELETE` y el digest.

      El siguiente ejemplo de script en bash elimina la etiqueta `latest` de `yourusername/helloworld` en Docker Hub. Reemplaza `yourusername` con tu nombre de usuario de Docker Hub y `dckr_pat` con tu token de acceso personal de Docker Hub.

      ```bash
      #!/bin/bash
  
      USERNAME=yourusername
      PASSWORD=dckr_pat
      REPO=yourusername/helloworld
      TAG=latest
  
      # Step 1: Get a bearer token
      TOKEN=$(curl -s -u "$USERNAME:$PASSWORD" \
        "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$REPO:pull,push,delete" \
        | jq -r .token)
  
      # Step 2 and 3: Get the manifest and extract the digest from response headers
      DIGEST=$(curl -sI -H "Authorization: Bearer $TOKEN" \
        -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
        https://registry-1.docker.io/v2/$REPO/manifests/$TAG \
        | grep -i Docker-Content-Digest | tr -d '\r' | awk '{print $2}')
  
      echo "Deleting manifest with digest: $DIGEST"
  
      # Step 4: Delete the manifest by digest
      curl -s -X DELETE \
        -H "Authorization: Bearer $TOKEN" \
        https://registry-1.docker.io/v2/$REPO/manifests/$DIGEST
  
      echo "Deleted image: $REPO@$DIGEST"
      ```
  
      Este ejemplo elimina el manifiesto de la etiqueta `latest`. Para eliminar por completo todas las referencias a una imagen, asegúrate de que ninguna otra etiqueta o referente apunte al mismo digest del manifiesto.


paths:
  /v2/{name}/manifests/{reference}:
    get:
      tags:
        - Manifests
      x-displayName: Manifests
      summary: Obtener el manifiesto de la imagen
      operationId: GetImageManifest
      description: |
        Obtén el manifiesto identificado por `name` y `reference`, donde `reference` puede ser una etiqueta (por ejemplo, `latest`) o un digest (por ejemplo, `sha256:...`).

        El manifiesto contiene metadatos sobre la imagen, incluidos los digests de la configuración y de las capas. Es necesario para descargar (pull) imágenes del registro.

        Este endpoint requiere autenticación. Usa la cabecera `Authorization: Bearer <token>`.
  
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # GET a manifest (by tag or digest)
            curl -H "Authorization: Bearer $TOKEN" \
                 -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
                 https://registry-1.docker.io/v2/library/ubuntu/manifests/latest
      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio de destino
          example: library/ubuntu
          schema:
            type: string
        - name: reference
          in: path
          required: true
          description: Etiqueta o digest del manifiesto de destino
          examples:
            by-tag:
              summary: Etiqueta
              value: latest
            by-digest:
              summary: Digest
              value: sha256:abc123def456...
          schema:
            type: string
        - name: Authorization
          in: header
          required: true
          description: Cabecera de autorización que cumple con RFC7235 (por ejemplo, `Bearer <token>`).
          schema:
            type: string
        - name: Accept
          in: header
          required: false
          description: |
            Tipos de medios que admite el cliente para el manifiesto.
        
            El registro admite los siguientes tipos de medios:
            - application/vnd.docker.distribution.manifest.v2+json
            - application/vnd.docker.distribution.manifest.list.v2+json
            - application/vnd.oci.image.manifest.v1+json
            - application/vnd.oci.image.index.v1+json
          schema:
            type: string

      responses:
        "200":
          description: El manifiesto se obtuvo correctamente.
          headers:
            Docker-Content-Digest:
              description: Digest del contenido del manifiesto devuelto.
              schema:
                type: string
            Content-Type:
              description: Tipo de medio del manifiesto devuelto.
              schema:
                type: string
          content:
            application/vnd.docker.distribution.manifest.v2+json:
              schema:
                type: object
                required:
                  - schemaVersion
                  - mediaType
                  - config
                  - layers
                properties:
                  schemaVersion:
                    type: integer
                    example: 2
                  mediaType:
                    type: string
                    example: application/vnd.docker.distribution.manifest.v2+json
                  config:
                    type: object
                    properties:
                      mediaType:
                        type: string
                        example: application/vnd.docker.container.image.v1+json
                      size:
                        type: integer
                        example: 7023
                      digest:
                        type: string
                        example: sha256:a3f3e...c1234
                  layers:
                    type: array
                    items:
                      type: object
                      properties:
                        mediaType:
                          type: string
                          example: application/vnd.docker.image.rootfs.diff.tar.gzip
                        size:
                          type: integer
                          example: 32654
                        digest:
                          type: string
                          example: sha256:bcf2...78901
              examples:
                docker-manifest:
                  summary: Manifiesto de imagen de Docker (esquema v2)
                  value:
                    {
                      "schemaVersion": 2,
                      "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
                      "config": {
                        "mediaType": "application/vnd.docker.container.image.v1+json",
                        "size": 7023,
                        "digest": "sha256:123456abcdef..."
                      },
                      "layers": [
                        {
                          "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                          "size": 32654,
                          "digest": "sha256:abcdef123456..."
                        },
                        {
                          "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                          "size": 16724,
                          "digest": "sha256:7890abcdef12..."
                        }
                      ]
                    }

        "400":
          description: Nombre o referencia no válidos.
        "401":
          description: Se requiere autenticación.
        "403":
          description: Acceso denegado.
        "404":
          description: Repositorio o manifiesto no encontrado.
        "429":
          description: Demasiadas solicitudes.


    put:
      tags:
        - Manifests
      summary: Subir el manifiesto de la imagen
      operationId: PutImageManifest
      description: |
        Sube el manifiesto de una imagen para una etiqueta o digest específicos. Esta operación registra un manifiesto en un repositorio, lo que permite descargarlo (pull) usando la referencia especificada.

        Este endpoint se usa típicamente después de haber subido todos los blobs de capas y de configuración al registro.

        El manifiesto debe cumplir con el esquema y el tipo de medio esperados. Para la versión 2 del esquema de manifiesto de imagen de Docker, usa:
        `application/vnd.docker.distribution.manifest.v2+json`

        Requiere autenticación mediante un token de portador con alcance `push` para el repositorio de destino.
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # PUT a manifest (tag = latest)
            curl -X PUT \
              -H "Authorization: Bearer $TOKEN" \
              -H "Content-Type: application/vnd.docker.distribution.manifest.v2+json" \
              --data-binary @manifest.json \
              https://registry-1.docker.io/v2/library/ubuntu/manifests/latest
      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio de destino
          example: library/ubuntu
          schema:
            type: string
        - name: reference
          in: path
          required: true
          description: Etiqueta o digest para asociar con el manifiesto subido
          examples:
            by-tag:
              summary: Etiqueta
              value: latest
            by-digest:
              summary: Digest
              value: sha256:abc123def456...
          schema:
            type: string
        - name: Authorization
          in: header
          required: true
          description: Cabecera de autorización que cumple con RFC7235 (por ejemplo, `Bearer <token>`).
          schema:
            type: string
        - name: Content-Type
          in: header
          required: true
          description: Tipo de medio del manifiesto que se está subiendo.
          schema:
            type: string
            example: application/vnd.docker.distribution.manifest.v2+json

      requestBody:
        required: true
        content:
          application/vnd.docker.distribution.manifest.v2+json:
            schema:
              type: object
              required:
                - schemaVersion
                - mediaType
                - config
                - layers
              properties:
                schemaVersion:
                  type: integer
                  example: 2
                mediaType:
                  type: string
                  example: application/vnd.docker.distribution.manifest.v2+json
                config:
                  type: object
                  required:
                    - mediaType
                    - size
                    - digest
                  properties:
                    mediaType:
                      type: string
                      example: application/vnd.docker.container.image.v1+json
                    size:
                      type: integer
                      example: 7023
                    digest:
                      type: string
                      example: sha256:123456abcdef...
                layers:
                  type: array
                  items:
                    type: object
                    required:
                      - mediaType
                      - size
                      - digest
                    properties:
                      mediaType:
                        type: string
                        example: application/vnd.docker.image.rootfs.diff.tar.gzip
                      size:
                        type: integer
                        example: 32654
                      digest:
                        type: string
                        example: sha256:abcdef123456...

            examples:
              sample-manifest:
                summary: Ejemplo de manifiesto de imagen de Docker (esquema v2)
                value:
                  {
                    "schemaVersion": 2,
                    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
                    "config": {
                      "mediaType": "application/vnd.docker.container.image.v1+json",
                      "size": 7023,
                      "digest": "sha256:123456abcdef..."
                    },
                    "layers": [
                      {
                        "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                        "size": 32654,
                        "digest": "sha256:abcdef123456..."
                      }
                    ]
                  }

      responses:
        "201":
          description: El manifiesto se creó correctamente.
          headers:
            Docker-Content-Digest:
              description: Digest del manifiesto almacenado.
              schema:
                type: string
              example: sha256:abcdef123456...
            Location:
              description: Ubicación canónica del manifiesto subido.
              schema:
                type: string
              example: /v2/library/ubuntu/manifests/latest
            Content-Length:
              description: Siempre cero.
              schema:
                type: integer
              example: 0
        "400":
          description: Nombre, referencia o manifiesto no válidos.
        "401":
          description: Se requiere autenticación.
        "403":
          description: Acceso denegado.
        "404":
          description: Repositorio no encontrado.
        "405":
          description: Operación no permitida.
        "429":
          description: Demasiadas solicitudes.
    head:
      tags:
        - Manifests
      summary: Comprobar si el manifiesto existe
      operationId: HeadImageManifest
      description: |
        Usa este endpoint para verificar si un manifiesto existe por etiqueta o digest.

        Esta es una operación ligera que solo devuelve cabeceras (sin cuerpo). Es útil para:
        - Comprobar la existencia de una versión de imagen específica.
        - Determinar el digest o el tamaño de un manifiesto antes de descargarlo o eliminarlo.

        Este endpoint requiere autenticación con alcance (scope) pull.

      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          example: library/ubuntu
          schema:
            type: string
        - name: reference
          in: path
          required: true
          description: Etiqueta o digest a comprobar
          examples:
            by-tag:
              summary: Etiqueta
              value: latest
            by-digest:
              summary: Digest
              value: sha256:abc123def456...
          schema:
            type: string
        - name: Authorization
          in: header
          required: true
          schema:
            type: string
          description: Token de portador para la autenticación
        - name: Accept
          in: header
          required: false
          schema:
            type: string
            example: application/vnd.docker.distribution.manifest.v2+json
          description: |
            Tipo de medio del manifiesto a comprobar. La respuesta coincidirá con uno de los tipos aceptados.
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # HEAD /v2/{name}/manifests/{reference}
            curl -I \
              -H "Authorization: Bearer $TOKEN" \
              -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
              https://registry-1.docker.io/v2/library/ubuntu/manifests/latest
      responses:
        "200":
          description: El manifiesto existe.
          headers:
            Content-Length:
              description: Tamaño del manifiesto en bytes
              schema:
                type: integer
              example: 7082
            Docker-Content-Digest:
              description: Digest del manifiesto
              schema:
                type: string
              example: sha256:abc123...
            Content-Type:
              description: Tipo de medio del manifiesto
              schema:
                type: string
              example: application/vnd.docker.distribution.manifest.v2+json
        "404":
          description: Manifiesto no encontrado.
        "401":
          description: Se requiere autenticación.
        "403":
          description: Acceso denegado.
        "429":
          description: Demasiadas solicitudes.
    delete:
      tags:
        - Manifests
      summary: Eliminar el manifiesto de la imagen
      operationId: DeleteImageManifest
      description: |
        Elimina el manifiesto de una imagen de un repositorio por digest.

        Solo se pueden eliminar los manifiestos no etiquetados o no referenciados. Si otra etiqueta u otra imagen sigue haciendo referencia al manifiesto, el registro devolverá `403 Forbidden`.

        Esta operación requiere acceso de tipo `delete` al repositorio.

        > **Note**
        >
        > Las operaciones de eliminación de manifiestos pueden tardar algún tiempo y podrían devolver un error `500 Internal Server Error`. El sistema reintenta automáticamente la eliminación en segundo plano. No se requiere intervención manual.
      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          example: tuusuariodehub/helloworld
          schema:
            type: string
        - name: reference
          in: path
          required: true
          description: Digest del manifiesto a eliminar (por ejemplo, `sha256:...`)
          example: sha256:abc123def456...
          schema:
            type: string
        - name: Authorization
          in: header
          required: true
          description: Token de portador con acceso de tipo `delete`
          schema:
            type: string
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # DELETE a manifest by digest
            curl -X DELETE \
              -H "Authorization: Bearer $TOKEN" \
              https://registry-1.docker.io/v2/yourusername/helloworld/manifests/sha256:abc123def456...
      responses:
        "202":
          description: Manifest deleted successfully. No content returned.
        "401":
          description: Authentication required.
        "403":
          description: Acceso denegado. Es posible que el manifiesto aún esté referenciado.
        "404":
          description: Manifiesto o repositorio no encontrado.
        "405":
          description: Solo se permite la eliminación basada en digest.
        "429":
          description: Demasiadas solicitudes.
  /v2/{name}/blobs/uploads/:
    post:
      tags:
        - Blobs
      summary: Iniciar la subida de un blob o intentar montar un blob de otro repositorio
      operationId: InitiateBlobUpload
      description: |
        Inicia una sesión de subida para un blob (capa o configuración) en un repositorio.

        Este es el primer paso para subir un blob. Devuelve una URL en la cabecera `Location` donde se puede subir el blob usando `PATCH` (por partes o chunked) o `PUT` (monolítico).

        En lugar de subir un blob, un cliente puede intentar montar un blob desde otro repositorio (si tiene acceso de lectura) incluyendo los parámetros de consulta `mount` y `from`.

        Si tiene éxito, el registro responde con `201 Created` y el blob se reutiliza sin volver a subirlo.

        Si el montaje falla, la subida procede de la forma habitual y devuelve un `202 Accepted`.

        Debes autenticarte con acceso de tipo `push` al repositorio de destino.
      x-codeSamples:
        - lang: Bash
          label: cURL (Initiate Standard Upload)
          source: |
            # Initiate a standard blob upload session
            curl -i -X POST \
              -H "Authorization: Bearer $TOKEN" \
              https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/

        - lang: Bash
          label: cURL (Cross-Repository Blob Mount)
          source: |
            # Attempt a cross-repository blob mount
            curl -i -X POST \
              -H "Authorization: Bearer $TOKEN" \
              "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/?mount=sha256:abc123def456...&from=library/busybox"

      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio de destino
          example: library/ubuntu
          schema:
            type: string
        - name: mount
          in: query
          required: false
          description: Digest del blob a montar desde otro repositorio
          schema:
            type: string
          example: sha256:abc123def456...
        - name: from
          in: query
          required: false
          description: Repositorio de origen desde el que montar el blob
          schema:
            type: string
          example: library/busybox
        - name: Authorization
          in: header
          required: true
          schema:
            type: string
          description: Token de portador para la autenticación con alcance `push`

      responses:
        "201":
          description: Blob montado correctamente desde otro repositorio.
          headers:
            Location:
              description: URL donde se puede acceder al blob montado
              schema:
                type: string
              example: /v2/library/ubuntu/blobs/sha256:abc123...
            Docker-Content-Digest:
              description: Digest canónico del blob montado
              schema:
                type: string
              example: sha256:abc123...
            Content-Length:
              description: Siempre cero
              schema:
                type: integer
              example: 0
        "202":
          description: Subida iniciada correctamente (alternativa si falla el montaje).
          headers:
            Location:
              description: URL de ubicación de subida para solicitudes `PATCH` o `PUT`
              schema:
                type: string
              example: /v2/library/ubuntu/blobs/uploads/abc123
            Docker-Upload-UUID:
              description: UUID generado por el servidor para la sesión de subida
              schema:
                type: string
              example: abc123
            Range:
              description: Rango de bytes de la subida actual (normalmente `0-0` al inicio)
              schema:
                type: string
              example: 0-0
            Content-Length:
              description: Siempre cero
              schema:
                type: integer
              example: 0
        "401":
          description: Se requiere autenticación.
        "403":
          description: Acceso denegado.
        "404":
          description: Repositorio no encontrado.
        "429":
          description: Demasiadas solicitudes.
  /v2/{name}/blobs/{digest}:
    head:
      tags:
        - Blobs
      summary: Comprobar la existencia del blob
      operationId: CheckBlobExists
      description: |
        Comprueba si un blob (capa o configuración) existe en el registro.

        Esto es útil antes de subir un blob para evitar duplicados.

        Si el blob está presente, el registro devuelve una respuesta `200 OK` con cabeceras como `Content-Length` y `Docker-Content-Digest`.

        Si el blob no existe, la respuesta será `404 Not Found`.
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # HEAD to check if a blob exists
            curl -I \
              -H "Authorization: Bearer $TOKEN" \
              https://registry-1.docker.io/v2/library/ubuntu/blobs/sha256:abc123...
      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          example: library/ubuntu
          schema:
            type: string
        - name: digest
          in: path
          required: true
          description: Digest del blob
          schema:
            type: string
          example: sha256:abc123def4567890...
        - name: Authorization
          in: header
          required: true
          description: Token de portador con alcance pull o push
          schema:
            type: string
          example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...

      responses:
        "200":
          description: El blob existe
          headers:
            Content-Length:
              description: Tamaño del blob en bytes
              schema:
                type: integer
              example: 32654
            Docker-Content-Digest:
              description: Digest del blob
              schema:
                type: string
              example: sha256:abc123def4567890...
            Content-Type:
              description: Tipo MIME del contenido del blob
              schema:
                type: string
              example: application/octet-stream
          content:
            application/json:
              examples:
                blob-check-request:
                  summary: Ejemplo de solicitud
                  value:
                    method: HEAD
                    url: /v2/library/ubuntu/blobs/sha256:abc123def4567890...
                    headers:
                      Authorization: Bearer <token>
                      Accept: '*/*'
                blob-check-response:
                  summary: Ejemplo de cabeceras de respuesta 200
                  value:
                    status: 200 OK
                    headers:
                      Docker-Content-Digest: sha256:abc123def4567890...
                      Content-Length: 32654
                      Content-Type: application/octet-stream

        "404":
          description: Blob no encontrado
        "401":
          description: Se requiere autenticación
        "403":
          description: Acceso denegado
        "429":
          description: Demasiadas solicitudes
    get:
      tags:
        - Blobs
      summary: Recuperar blob
      operationId: GetBlob
      description: |
        Descarga del registro el blob identificado por el digest.

        Los blobs incluyen capas de imágenes y objetos de configuración. Los clientes deben usar el digest del manifiesto para recuperar un blob.

        Este endpoint puede devolver una redirección temporal `307 Temporary Redirect` a una CDN o ubicación de almacenamiento. Los clientes deben seguir la redirección para obtener el contenido real del blob.

        El contenido del blob es típicamente un archivo tar comprimido con gzip (para capas) o JSON (para configuraciones). El tipo MIME suele ser `application/octet-stream`.
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # GET (download) a blob
            curl -L \
              -H "Authorization: Bearer $TOKEN" \
              https://registry-1.docker.io/v2/library/ubuntu/blobs/sha256:abc123... \
              -o layer.tar.gz
      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          example: library/ubuntu
          schema:
            type: string
        - name: digest
          in: path
          required: true
          description: Digest del blob
          schema:
            type: string
          example: sha256:abc123def456...
        - name: Authorization
          in: header
          required: true
          schema:
            type: string
          description: Token de portador con alcance pull
          example: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...

      responses:
        "200":
          description: El contenido del blob se devuelve directamente
          headers:
            Content-Length:
              description: Tamaño del blob en bytes
              schema:
                type: integer
              example: 32768
            Content-Type:
              description: Tipo MIME del blob
              schema:
                type: string
              example: application/octet-stream
            Docker-Content-Digest:
              description: Digest del blob devuelto
              schema:
                type: string
              example: sha256:abc123def456...
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
              examples:
                small-layer:
                  summary: Ejemplo de blob binario (capa de archivo tar comprimido con gzip)
                  value: "<binary data not shown>"

        "307":
          description: Redirección temporal a la ubicación del blob
          headers:
            Location:
              description: URL de redirección para la descarga del blob (por ejemplo, S3 o CDN)
              schema:
                type: string
              example: https://cdn.docker.io/blobs/library/ubuntu/abc123...
        "401":
          description: Se requiere autenticación
        "403":
          description: Acceso denegado
        "404":
          description: Blob no encontrado
        "429":
          description: Demasiadas solicitudes
  /v2/{name}/blobs/uploads/{uuid}:
    get:
      tags:
        - Blobs
      summary: Obtener el estado de la subida del blob
      operationId: GetBlobUploadStatus
      description: |
        Recupera el estado actual de una subida de blob en curso.

        Esto es útil para:
        - Reanudar una subida interrumpida.
        - Determinar cuántos bytes se han aceptado hasta ahora.
        - Reintentar desde el desplazamiento (offset) correcto en subidas por partes (chunked).

        La respuesta incluye la cabecera `Range` que indica el rango de bytes recibido hasta ahora, y un `Docker-Upload-UUID` para identificar la sesión.
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # GET upload status
            curl -I \
              -H "Authorization: Bearer $TOKEN" \
              https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123
      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          example : library/ubuntu
          schema:
            type: string
        - name: uuid
          in: path
          required: true
          description: UUID de la sesión de subida
          schema:
            type: string
          example: abc123
        - name: Authorization
          in: header
          required: true
          schema:
            type: string
          example: Bearer eyJhbGciOi...

      responses:
        "204":
          description: Subida en curso. No se devuelve ningún cuerpo.
          headers:
            Range:
              description: Rango de bytes actual subido (inclusive)
              schema:
                type: string
              example: 0-16383
            Docker-Upload-UUID:
              description: UUID de la sesión de subida
              schema:
                type: string
              example: abc123
            Location:
              description: URL para continuar o completar la subida
              schema:
                type: string
              example: /v2/library/ubuntu/blobs/uploads/abc123
        "401":
          description: Se requiere autenticación
        "403":
          description: Acceso denegado
        "404":
          description: Sesión de subida no encontrada
        "429":
          description: Demasiadas solicitudes

    put:
      tags:
        - Blobs
      summary: Completar la subida del blob
      operationId: CompleteBlobUpload
      description: |
        Completa la subida de un blob finalizando una sesión de subida.

        Esta solicitud debe incluir el parámetro de consulta `digest` y opcionalmente la última parte de los datos. Cuando el registro recibe esta solicitud, verifica el digest y almacena el blob.

        Este endpoint admite:
        - Subidas monolíticas (subir el blob completo en esta solicitud)
        - Finalización de subidas por partes (última parte más el `digest`)

      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # PUT – complete upload (monolithic or final chunk)
            curl -X PUT \
              -H "Authorization: Bearer $TOKEN" \
              -H "Content-Type: application/octet-stream" \
              --data-binary @layer.tar.gz \
              "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123?digest=sha256:abcd1234..."


      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          schema:
            type: string
          example: library/ubuntu
        - name: uuid
          in: path
          required: true
          description: UUID de la sesión de subida devuelto en la solicitud POST
          schema:
            type: string
          example: abc123
        - name: digest
          in: query
          required: true
          description: Digest del blob subido
          schema:
            type: string
          example: sha256:abcd1234...
        - name: Authorization
          in: header
          required: true
          schema:
            type: string
          example: Bearer eyJhbGciOi...

      requestBody:
        required: false
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
            examples:
              layer-upload:
                summary: Blob de archivo tar de capa
                value: "<binary data not shown>"

      responses:
        "201":
          description: Subida completada correctamente
          headers:
            Docker-Content-Digest:
              description: Digest canónico del blob almacenado
              schema:
                type: string
              example: sha256:abcd1234...
            Location:
              description: URL donde el blob está ahora accesible
              schema:
                type: string
              example: /v2/library/ubuntu/blobs/sha256:abcd1234...
            Content-Length:
              description: Siempre cero para subidas completadas
              schema:
                type: integer
              example: 0
        "400":
          description: Digest no válido o faltan parámetros
        "401":
          description: Se requiere autenticación
        "403":
          description: Acceso denegado
        "404":
          description: Sesión de subida no encontrada
        "416":
          description: El rango solicitado no es satisfactorio (si se usa en modo por partes)
        "429":
          description: Demasiadas solicitudes

    patch:
      tags:
        - Blobs
      summary: Subir una parte del blob
      operationId: UploadBlobChunk
      description: |
        Sube una parte de un blob a una sesión de subida activa.

        Usa este método para **subidas por partes**, especialmente para blobs grandes o al reanudar subidas interrumpidas.

        El cliente envía datos binarios usando `PATCH`, incluyendo opcionalmente una cabecera `Content-Range`.

        Después de aceptar cada parte, el registro devuelve una respuesta `202 Accepted` con:
        - `Range`: rango de bytes actual almacenado
        - `Docker-Upload-UUID`: identificador de la sesión de subida
        - `Location`: URL para continuar la subida o finalizar con `PUT`
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # PATCH – upload a chunk (first 64 KiB)
            curl -X PATCH \
              -H "Authorization: Bearer $TOKEN" \
              -H "Content-Type: application/octet-stream" \
              --data-binary @chunk-0.bin \
              "https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123"
      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          schema:
            type: string
          example: library/ubuntu
        - name: uuid
          in: path
          required: true
          description: UUID de la sesión de subida
          schema:
            type: string
          example: abc123
        - name: Authorization
          in: header
          required: true
          schema:
            type: string
          example: Bearer eyJhbGciOi...
        - name: Content-Range
          in: header
          required: false
          schema:
            type: string
          example: bytes 0-65535
          description: Opcional. Rango de bytes de la parte que se está enviando

      requestBody:
        required: true
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
            examples:
              chunk-0:
                summary: Subir la parte 0 de un blob
                value: "<binary data not shown>"

      responses:
        "202":
          description: Parte aceptada y almacenada
          headers:
            Location:
              description: URL para continuar o finalizar la subida
              schema:
                type: string
              example: /v2/library/ubuntu/blobs/uploads/abc123
            Range:
              description: Rango de bytes subido hasta ahora (inclusive)
              schema:
                type: string
              example: 0-65535
            Docker-Upload-UUID:
              description: UUID de la sesión de subida
              schema:
                type: string
              example: abc123
        "400":
          description: Contenido o rango mal formados
        "401":
          description: Se requiere autenticación
        "403":
          description: Acceso denegado
        "404":
          description: Sesión de subida no encontrada
        "416":
          description: Error de rango (por ejemplo, parte fuera de orden)
        "429":
          description: Demasiadas solicitudes
    delete:
      tags:
        - Blobs
      summary: Cancelar la subida del blob
      operationId: CancelBlobUpload
      description: |
        Cancela una sesión de subida de blob en curso.

        Esta operación descarta cualquier dato que se haya subido e invalida la sesión de subida.

        Usa esto cuando:
        - Una subida falla o se aborta a mitad del proceso.
        - El cliente quiere limpiar sesiones de subida no utilizadas.

        Después de la cancelación, el UUID ya no es válido y se debe emitir un nuevo `POST` para reiniciar la subida.

      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            # DELETE – cancel an upload session
            curl -X DELETE \
              -H "Authorization: Bearer $TOKEN" \
              https://registry-1.docker.io/v2/library/ubuntu/blobs/uploads/abc123`

      parameters:
        - name: name
          in: path
          required: true
          description: Nombre del repositorio
          schema:
            type: string
          example: library/ubuntu
        - name: uuid
          in: path
          required: true
          description: UUID de la sesión de subida
          schema:
            type: string
          example: abc123
        - name: Authorization
          in: header
          required: true
          schema:
            type: string
          example: Bearer eyJhbGciOi...

      responses:
        "204":
          description: Sesión de subida cancelada correctamente. No se devuelve ningún cuerpo.
          headers:
            Content-Length:
              description: Siempre cero
              schema:
                type: integer
              example: 0
        "401":
          description: Se requiere autenticación
        "403":
          description: Acceso denegado
        "404":
          description: Sesión de subida no encontrada
        "429":
          description: Demasiadas solicitudes


x-tagGroups:
  - name: General
    tags:
      - overview
      - authentication
      - pull
      - push
      - delete
  - name: API
    tags:
      - Manifests
      - Blobs
