API Reference (S3)
A catalog of the S3-compatible API operations OtterStorage supports, with their endpoint, authentication, and examples.
OtterStorage exposes an S3-compatible API, so you can use the AWS SDK, the CLI, or any compatible client without proprietary software. This reference lists the supported operations, grouped by scope (service, bucket, object, versioning, multipart, and Object Lock), and shows how to authenticate and which endpoint to send your requests to. Remember that we don't charge for requests or deletions, so you can list, query, and clean up with no per-operation cost.
Endpoint and region
All requests are sent to the OtterStorage base endpoint:
https://es-mad-1.s3.otterstorage.io
- Base endpoint:
https://es-mad-1.s3.otterstorage.io(HTTPS required). - Example region:
eu-mad. Specify it in your client's configuration and inLocationConstraintwhen creating buckets. - Credentials: one
access keyand onesecret keyper bucket, issued from the console.
Addressing style
OtterStorage supports path-style, meaning the bucket name is part of the path rather than the subdomain:
https://es-mad-1.s3.otterstorage.io/mi-bucket/ruta/objeto.txt
Path-style works with any bucket name, including those that contain dots, and it's the easiest to use behind a proxy or in development environments. If your client defaults to virtual-hosted style, force it to path-style; for example, with the AWS SDK for Python (boto3):
import boto3
from botocore.config import Config
s3 = boto3.client(
"s3",
endpoint_url="https://es-mad-1.s3.otterstorage.io",
region_name="eu-mad",
aws_access_key_id="YOUR_ACCESS_KEY",
aws_secret_access_key="YOUR_SECRET_KEY",
config=Config(s3={"addressing_style": "path"}),
)
Authentication
OtterStorage uses AWS Signature Version 4 (SigV4) to sign requests. The official SDKs and CLI generate the signature automatically: you only need to configure your access key, your secret key, and the region. A signed request includes, among others, the following headers:
Authorization: AWS4-HMAC-SHA256 Credential=YOUR_ACCESS_KEY/20260611/eu-mad/s3/aws4_request, \
SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=...
x-amz-date: 20260611T120000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
host: es-mad-1.s3.otterstorage.io
The client's clock must be synchronized: a large drift from the server's time invalidates the signature. To configure the CLI step by step, see the AWS CLI guide.
Service
Account-level operations. OtterStorage access keys are scoped to a single bucket, so ListBuckets does not return the full list of the account's buckets: check your buckets in the console and work against the bucket whose name you already know.
Bucket operations
These create, query, and configure buckets and their policies.
Bucket lifecycle
ℹ️ Creating and deleting buckets is done from the console, not via the API: access keys are scoped to a single bucket. Through the API you operate on objects and query the bucket you have access to.
CreateBucket,DeleteBucket— managed from the console (not available with bucket keys).HeadBucket— checks the bucket's existence and your permissions.GetBucketLocation— returns the bucket's region.
# Comprobar que el bucket existe y tienes acceso
aws --profile otter s3api head-bucket --bucket mi-bucket
# Consultar la región del bucket
aws --profile otter s3api get-bucket-location --bucket mi-bucket
Bucket versioning
PutBucketVersioning— enables or suspends versioning.GetBucketVersioning— queries the versioning status.
aws --profile otter s3api put-bucket-versioning \
--bucket mi-bucket \
--versioning-configuration Status=Enabled
Bucket policies
PutBucketPolicy— defines an access policy in JSON format.GetBucketPolicy— retrieves the current policy.DeleteBucketPolicy— removes the bucket's policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LecturaPublicaDeAssets",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mi-bucket/public/*"
}
]
}
Lifecycle rules
PutBucketLifecycleConfiguration— defines expiration and cleanup rules.GetBucketLifecycleConfiguration— queries the active rules.DeleteBucketLifecycle— removes the entire lifecycle configuration.
Lifecycle rules let you, for example, expire old versions or abort incomplete multipart uploads automatically. See the lifecycle guide for complete examples.
Bucket ACL and tags
GetBucketAcl/PutBucketAcl— query and define the bucket's access control list.PutBucketTagging/GetBucketTagging— assign and query the bucket's tags (key/value).
CORS
PutBucketCors— configures the CORS rules for browser access.GetBucketCors— queries the current CORS configuration.
{
"CORSRules": [
{
"AllowedOrigins": ["https://app.ejemplo.com"],
"AllowedMethods": ["GET", "PUT"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3000
}
]
}
Object operations
These upload, download, copy, list, and delete objects, and manage their ACLs and tags.
PutObject— uploads an object (supports metadata,Content-Type, and, with Object Lock, retention).GetObject— downloads an object; supports range downloads (Range).HeadObject— retrieves only the object's metadata and headers.DeleteObject— deletes an object (or creates a delete marker if versioning is enabled).DeleteObjects— deletes up to 1000 objects in a single request.CopyObject— copies an object between keys or buckets without downloading it.ListObjectsV2— lists objects by prefix (pagination withcontinuation-token; recommended).ListObjects— the original variant with markers (marker); kept for compatibility.GetObjectAcl/PutObjectAcl— query and define an object's ACL.GetObjectTagging/PutObjectTagging— query and assign tags to an object.
# Subir un objeto con su tipo de contenido
aws --profile otter s3api put-object \
--bucket mi-bucket \
--key docs/manual.pdf \
--body ./manual.pdf \
--content-type application/pdf
# Copiar un objeto a otra clave del mismo bucket
aws --profile otter s3api copy-object \
--bucket mi-bucket \
--copy-source mi-bucket/docs/manual.pdf \
--key docs/manual-copia.pdf
# Listar por prefijo con ListObjectsV2
aws --profile otter s3api list-objects-v2 \
--bucket mi-bucket \
--prefix docs/ \
--max-keys 100
Batch deletion with DeleteObjects takes the list of keys in the request body:
aws --profile otter s3api delete-objects \
--bucket mi-bucket \
--delete '{"Objects":[{"Key":"docs/a.txt"},{"Key":"docs/b.txt"}]}'
Because we don't bill for requests or deletions, you can list and clean up as many objects as you need with no per-operation cost.
Versioning
With versioning enabled, each object retains its previous versions, identified by versionId. This protects against accidental overwrites and deletions.
ListObjectVersions— lists all versions and delete markers in a bucket or prefix.GetObjectwith?versionId=— downloads a specific version of an object.DeleteObjectwith?versionId=— permanently deletes a specific version.
# Listar todas las versiones
aws --profile otter s3api list-object-versions --bucket mi-bucket
# Descargar una versión concreta
aws --profile otter s3api get-object \
--bucket mi-bucket \
--key docs/manual.pdf \
--version-id LA_VERSION_ID \
./manual-anterior.pdf
# Borrar permanentemente una versión concreta
aws --profile otter s3api delete-object \
--bucket mi-bucket \
--key docs/manual.pdf \
--version-id LA_VERSION_ID
For more detail on how to enable it and restore versions, see the versioning guide.
Multipart upload
Multipart upload splits a large object into parts that are transferred separately (and in parallel) and then assembled on the server. It's the recommended approach for large files and for resuming transfers.
CreateMultipartUpload— starts an upload and returns anUploadId.UploadPart— uploads a numbered part of the object.UploadPartCopy— creates a part by copying a range from another existing object.CompleteMultipartUpload— assembles the parts and finalizes the object.AbortMultipartUpload— cancels the upload and discards the parts already sent.ListMultipartUploads— lists a bucket's in-progress multipart uploads.ListParts— lists the parts already uploaded for anUploadId.
# Ver subidas multiparte pendientes
aws --profile otter s3api list-multipart-uploads --bucket mi-bucket
# Abortar una subida concreta (no tiene coste de operación)
aws --profile otter s3api abort-multipart-upload \
--bucket mi-bucket \
--key media/video.mov \
--upload-id EL_UPLOAD_ID
The high-level commands (aws s3 cp and aws s3 sync) use multipart automatically when a file exceeds the configured threshold. A lifecycle rule can automatically abort incomplete uploads after a certain time.
Object Lock
Object Lock applies a WORM model (Write Once, Read Many) that prevents an object from being deleted or overwritten until a given date or while a legal hold is active. It requires a bucket with Object Lock enabled, which also enables versioning.
PutObjectLockConfiguration/GetObjectLockConfiguration— define and query the bucket's default retention.PutObjectRetention/GetObjectRetention— set and query the retention (GOVERNANCEorCOMPLIANCEmode) of a version.PutObjectLegalHold/GetObjectLegalHold— enable, disable, and query a legal hold independent of the date.
# Aplicar retención COMPLIANCE a un objeto
aws --profile otter s3api put-object-retention \
--bucket bucket-worm \
--key contratos/2026.pdf \
--retention '{"Mode":"COMPLIANCE","RetainUntilDate":"2027-06-11T00:00:00Z"}'
# Activar una retención legal sobre el objeto
aws --profile otter s3api put-object-legal-hold \
--bucket bucket-worm \
--key contratos/2026.pdf \
--legal-hold Status=ON
See the Object Lock guide and the legal hold guide for the details of each mode.
Presigned URLs
A presigned URL embeds a temporary SigV4 signature in the URL itself, so you can share a private object (or allow an upload) for a limited time without exposing your keys. The signature is client-side: OtterStorage verifies it when it receives the request, so no prior call to the server is needed to generate it.
# Generar una URL de descarga válida 1 hora (3600 s)
aws --profile otter s3 presign s3://mi-bucket/docs/manual.pdf --expires-in 3600
You can also generate presigned URLs with any SDK; for example, an upload URL with boto3:
url = s3.generate_presigned_url(
"put_object",
Params={"Bucket": "mi-bucket", "Key": "uploads/foto.jpg"},
ExpiresIn=900,
)
Request billing
With OtterStorage, API requests are not billed: we don't charge for read, write, list, or delete operations. You can paginate through large listings, check metadata with HeadObject, or clean up versions and incomplete uploads without adding any per-operation cost to your bill.
Next steps
- Configure your terminal client with the AWS CLI guide.
- Protect your data against deletions with versioning.
- Enforce WORM compliance with Object Lock.
Need more context on buckets, keys, or regions? Return to the documentation.
Ready to try it out?
Create your account and get your keys in minutes.