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

# Buckets

> Crear un bucket, apuntar un cliente de S3 a él y lo que se necesita para eliminar uno.

<a id="creating-a-bucket" />

## Crear un bucket

<Tabs>
  <Tab title="Console">
    Vaya a **Storage → Buckets** y elija **Create Bucket**. **Bucket Name** es lo único que tiene que rellenar; **Versioning**, **Default
    encryption**, **Deletion protection** y **Tags** están en el mismo formulario.

    Estos extras se aplican como llamadas separadas una vez que el bucket existe, por lo que el bucket se crea incluso si uno de ellos falla, y la consola le dice cuál lo hizo.
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    POST https://storage.sa-saopaulo-1.basaltic.sh/v1/buckets
    { "name": "my-app-assets" }
    ```
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    basaltic storage bucket create --name my-app-assets
    ```

    Añade `--object-lock-enabled` aquí si lo necesitas — solo puede montar en la llamada que crea el bucket.
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    b, err := storage.New(cfg).CreateBucket(ctx, &storage.CreateBucketRequest{
        Name: "my-app-assets",
    })
    ```
  </Tab>
</Tabs>

Los nombres de los depósitos siguen las reglas de S3 y se comprueban en su totalidad:

<ResponseField name="name" type="3–63 characters" required>
  Letras minúsculas, dígitos y guiones. Debe comenzar y terminar con una letra o un dígito, no debe contener un **guion doble** (`--`) y no debe tener la forma de una dirección IP.
</ResponseField>

<Warning>
  **Un nombre de depósito es único en toda la región, no solo en tu cuenta.** Un nombre que ya tiene otra cuenta devuelve `409`. Crear un bucket que ya posees es una operación correcta que no cambia nada, por lo que una creación repetida es segura.
</Warning>

El recuento de buckets está limitado por la cuota de `buckets` de su organización; agotarla también es un `409` en crear.

<a id="object-lock-has-to-be-decided-here" />

### El bloqueo de objetos tiene que ser decidido aquí

```bash theme={null}
POST /v1/buckets
{ "name": "audit-archive", "object_lock_enabled": true }
```

<Warning>
  **Bloqueo de objetos solo se puede habilitar en la creación.** No hay ninguna llamada que lo active más tarde — tendrías que crear un nuevo bucket y copiar los objetos en el mismo — pero habilitarlo también activa el control de versiones, porque un bloqueo no tiene nada que mantener sin versiones.
</Warning>

`PUT /v1/buckets/{bucket}/object-lock` actualiza la *regla de retención predeterminada* en un bucket que ya tiene Object Lock habilitado. Contra un bucket que no lo hace, es un `409` — `object lock must be enabled at bucket creation`.

<Note>
  **Activar Object Lock es solo para API.** Tiene que ser ejecutado en la llamada que crea el bucket, y el formulario **Create Bucket** de la consola no lo envía — el bucket se crea sin Object Lock, y la configuración de seguimiento se rechaza con ese mismo `409`. Cree el bucket a través de la API cuando necesite Object Lock.

  En un depósito que ya lo tiene, la consola edita la regla: la tarjeta **Object Lock** en la pestaña **Settings** del depósito lleva la **Default retention rule**, con un **Mode** y un **Retention period**.
</Note>

<a id="pointing-an-s3-client-at-it" />

## Apuntando un cliente de S3 a él

Establezca un punto final personalizado y firme con su clave de acceso de Basaltic. Nada más sobre el cliente cambia.

<CodeGroup>
  ```python boto3 theme={null}
  import boto3
  from botocore.config import Config

  s3 = boto3.client(
      "s3",
      endpoint_url="https://objects.sa-saopaulo-1.basaltic.cloud",
      aws_access_key_id=ACCESS_KEY_ID,
      aws_secret_access_key=SECRET_ACCESS_KEY,
      region_name="sa-saopaulo-1",
      config=Config(signature_version="s3v4"),
  )

  s3.put_object(Bucket="my-app-assets", Key="images/logo.png", Body=data)
  ```

  ```bash AWS CLI theme={null}
  aws --endpoint-url https://objects.sa-saopaulo-1.basaltic.cloud \
      s3 cp ./logo.png s3://my-app-assets/images/logo.png
  ```

  ```python Temporary credentials theme={null}
  s3 = boto3.client(
      "s3",
      endpoint_url="https://objects.sa-saopaulo-1.basaltic.cloud",
      aws_access_key_id=creds.access_key_id,
      aws_secret_access_key=creds.secret_access_key,
      aws_session_token=creds.session_token,   # required for STS credentials
      region_name="sa-saopaulo-1",
      config=Config(signature_version="s3v4"),
  )
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Credenciales" icon="key-round">
    Las mismas teclas de acceso que usas en todas partes. La clave de larga duración de una cuenta de servicio no necesita nada adicional; las credenciales temporales de STS (una sesión de rol o una sesión de usuario) también deben llevar el token de sesión, y se rechazan sin él.

    Vea [authentication](/es/authentication) para obtener cada uno.
  </Accordion>

  <Accordion title="Estilo de dirección" icon="route">
    Ambos estilos funcionan. Virtual-hosted (`https://my-app-assets.objects.sa-saopaulo-1.basaltic.cloud/key`) es lo que la mayoría de los SDKs predeterminan; path-style (`https://objects.sa-saopaulo-1.basaltic.cloud/my-app-assets/key`) está disponible a través de la opción de estilo de dirección de su cliente.
  </Accordion>

  <Accordion title="La cadena de la región" icon="globe">
    Establezca `region_name` al código de región Basaltic. El valor no se compara con la región que sirve la solicitud — solo tiene que coincidir con la que su cliente firmó — por lo que una herramienta con conexión a `us-east-1` aún funciona. `GetBucketLocation` informa la región real.
  </Accordion>

  <Accordion title="URLs sesgadas y prefirmadas" icon="clock">
    Una solicitud firmada debe estar dentro de los **15 minutos** del reloj del servidor, o se rechaza como demasiado sesgada. Las URL prefirmadas son compatibles con una caducidad entre 1 segundo y **7 días**, y una URL con fecha futura más allá de la tolerancia de sesgo se rechaza en lugar de volverse válida más tarde.
  </Accordion>
</AccordionGroup>

<a id="what-the-s3-endpoint-serves" />

### Qué sirve el punto final de S3

El punto final se verifica con un SDK de AWS real en lugar de una especificación propia: si boto3 puede hacerlo y obtener los códigos de error de S3, funciona. Lo que se enruta hoy:

<Columns cols={2}>
  <Card title="Buckets" icon="boxes">
    ListBuckets, CreateBucket, HeadBucket, DeleteBucket, GetBucketLocation y los subrecursos `?policy`, `?cors`, `?lifecycle`, `?versioning`, `?encryption`, `?tagging`, `?object-lock` y `?acl`.
  </Card>

  <Card title="Objetos" icon="file">
    PutObject, GetObject (incluidas las solicitudes de rango), HeadObject, DeleteObject, DeleteObjects, CopyObject, ListObjects, ListObjectsV2, ListObjectVersions y los subrecursos `?tagging`, `?retention`, `?legal-hold` y `?acl`.
  </Card>

  <Card title="Multipart" icon="layers">
    Crear carga de múltiples partes, carga de parte, copia de parte de carga, lista de partes, lista de cargas de múltiples partes, completa carga de múltiples partes, cancelar carga de múltiples partes.
  </Card>

  <Card title="Firma de carga útil" icon="shield">
    Cargas útiles firmadas, `UNSIGNED-PAYLOAD`, y firmadas `aws-chunked` cargas de transmisión. El cuerpo se vuelve a hash a medida que se transmite, por lo que un cuerpo que no coincide con lo que se firmó se rechaza a mitad de vuelo.
  </Card>
</Columns>

Cualquier cosa fuera de esa lista responde `NotImplemented`. Las solicitudes de comprobación previa `OPTIONS` se responden sin una firma, porque los navegadores nunca las firman.

<a id="deleting-a-bucket" />

## Eliminar un bucket

`DELETE /v1/buckets/{bucket}` hace dos cosas muy diferentes dependiendo de si la protección de eliminación está activada. La protección está **desactivada de forma predeterminada** para la paridad de S3: a diferencia de los secretos y KMS, los depósitos no protegidos no tienen ventana de recuperación.

<Tabs>
  <Tab title="Protección desactivada (predeterminado)">
    El bucket debe estar **vacío**. Cualquier objeto, versión o carga de varias partes en curso que quede hace que sea un `409 BucketNotEmpty`. Un depósito vacío se elimina inmediatamente y se libera la ranura de cuota.
  </Tab>

  <Tab title="Protección en el trabajo">
    La eliminación está **programada** para el final de la ventana de recuperación en lugar de realizarse, y se acepta independientemente de que el depósito esté vacío o no. `deleted_at` registra cuando solicitaste la eliminación y `scheduled_purge_at` registra la fecha límite de purga. Los depósitos que ya estaban en una ventana de recuperación cuando se introdujeron estos campos conservan su fecha límite y tienen un `deleted_at` nulo. Ambas marcas de tiempo se borran al restaurar. `POST /v1/buckets/{bucket}/restore` lo cancela en cualquier momento antes de esa fecha límite. En la consola, el depósito programado lleva una acción **Cancel deletion** que hace lo mismo. Llamar a delete de nuevo mientras una eliminación ya está programada es una no-op, no una segunda ventana.

    <Warning>
      Cuando la fecha límite pasa, el depósito se vacía y se purga — **sus objetos van con él**. La protección le ofrece una ventana para cambiar de opinión, no una negativa a eliminar un depósito con datos en él.
    </Warning>
  </Tab>
</Tabs>

<Tabs>
  <Tab title="Console">
    La tarjeta **Deletion protection** en la pestaña **Settings** del depósito es un interruptor junto a **Recovery window (days)**. **Save** aplica ambos.
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    PUT /v1/buckets/{bucket}/deletion-protection
    { "enabled": true, "recovery_window_days": 14 }
    ```
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    basaltic storage bucket set-deletion-protection <bucket> \
      --enabled --recovery-window-days 14
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    err := storage.New(cfg).PutBucketDeletionProtection(ctx, bucket,
        &storage.PutBucketDeletionProtectionRequest{
            Enabled:      true,
            RecoveryWindowDays: basaltic.Int(14),
        })
    ```
  </Tab>
</Tabs>

`recovery_window_days` acepta números enteros de **1–30**. Omitir cada campo de ventana utiliza **7 días**. Los valores no válidos devuelven `400`, incluso cuando se desactiva la protección.

<a id="release-note-recovery-fields" />

### Nota de la versión: campos de recuperación

Las respuestas del depósito exponen `recovery_window_days`, `scheduled_purge_at` y `deleted_at` nullable. Protegido DELETE devuelve `200` con `scheduled_purge_at`; inmediato DELETE devuelve `204`.

<a id="breaking-behavior-change-invalid-windows-return-400" />

### Cambio de comportamiento de ruptura: ventanas no válidas devuelven 400

El servicio previamente silenciosamente sujetaba las ventanas: los valores por debajo de 1 seleccionaban 7 días, y los valores por encima de 30 seleccionaban 30 días. Ahora los rechaza con `400` en su lugar. Por ejemplo, si se solicitan 60 días, se produce un error; ya no programa una purga después de solo 30 días. El cero explícito también es inválido; omita los campos de la ventana para seleccionar el valor predeterminado de 7 días. Los días fraccionarios no son válidos. Actualizar los llamadores que dependían de la sujeción por separado de la adopción de los nuevos nombres de campo.

Durante una implementación continua, las instancias de servicio antiguas pueden seguir aplicando su antiguo comportamiento de sujeción; el rechazo es universal una vez que se actualizan todas las instancias.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.