Skip to main content

S3 API reference

The S3 API served by mantad, the Triton Cloud object store, on port 7443. For the concepts behind workspaces and keys, see How object storage works.

Endpoint and addressing​

PropertyValue
Endpointhttps://s3.<DOMAIN>:7443 when the cloud has an ACME-enabled DNS zone. Otherwise http://<IP>:7443 on a private address. Your operator provides it.
AddressingPath-style only: /<BUCKET>/<KEY>. A bucket in the Host header is not parsed.
RegionAny region string signs successfully. GetBucketLocation returns the configured region, default us-east-1.
Server headerServer: mantad/<VERSION>. Every response carries x-amz-request-id and x-amz-id-2.

Authentication​

MethodBehavior
Signature Version 4, Authorization headerSupported. x-amz-date and x-amz-content-sha256 are required. The scope's service is s3 or sts.
Signature Version 4, presigned querySupported. X-Amz-Expires is 1 to 604800 seconds. Outside that range: 403 AccessDenied. An expired URL: 403 AccessDenied, Request has expired.
Signature Version 2, Authorization headerRefused. 403 InvalidDigest, or 400 InvalidArgument when the header has no :.
Session credentialsGetSessionToken, AssumeRole, and GetCallerIdentity are served as STS form posts to /. Session keys start with MSIA and need x-amz-security-token. Duration is 900 to 129600 seconds, default 43200. AssumeRoleWithWebIdentity returns 501.
AnonymousUnsigned requests are evaluated against bucket ACLs, bucket policy, and public access block. Anonymous CreateBucket returns 403.

Clock skew tolerance is 15 minutes. Beyond it: 403 RequestTimeTooSkewed.

Payload signing​

x-amz-content-sha256Behavior
SHA-256 hex digestAccepted. The body is checked against the digest.
UNSIGNED-PAYLOADAccepted with a Content-Length.
STREAMING-AWS4-HMAC-SHA256-PAYLOAD, STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILERAccepted. Each chunk signature is checked. A bad chunk: 403 SignatureDoesNotMatch.
STREAMING-UNSIGNED-PAYLOAD-TRAILERRefused with 403 AccessDenied unless the operator set MANTAD_ALLOW_STREAMING_UNSIGNED_PAYLOAD=true.
ECDSA streaming501 NotImplemented.

Operations​

GroupImplemented operations
ServiceListBuckets
BucketCreateBucket, HeadBucket, DeleteBucket, GetBucketLocation, GetBucketVersioning, PutBucketVersioning
ObjectPutObject, GetObject, HeadObject, DeleteObject, DeleteObjects, CopyObject, PostObject (browser form upload)
ListingListObjects, ListObjectsV2, ListObjectVersions
MultipartCreateMultipartUpload, UploadPart, UploadPartCopy, CompleteMultipartUpload, AbortMultipartUpload, ListParts, ListMultipartUploads
LifecycleGetBucketLifecycleConfiguration, PutBucketLifecycleConfiguration, DeleteBucketLifecycle
ACLGetBucketAcl, PutBucketAcl, GetObjectAcl, PutObjectAcl
CORSGetBucketCors, PutBucketCors, DeleteBucketCors, and OPTIONS preflight
TaggingGetBucketTagging, PutBucketTagging, DeleteBucketTagging, GetObjectTagging, PutObjectTagging, DeleteObjectTagging
Bucket policyGetBucketPolicy, PutBucketPolicy, DeleteBucketPolicy, GetBucketPolicyStatus
Object LockGetObjectLockConfiguration, PutObjectLockConfiguration, GetObjectRetention, PutObjectRetention, GetObjectLegalHold, PutObjectLegalHold
Public access blockGetPublicAccessBlock, PutPublicAccessBlock, DeletePublicAccessBlock

GetObjectTorrent returns 404 NoSuchKey. GetBucketOwnershipControls returns 404 OwnershipControlsNotFoundError.

Every other S3 operation returns 501 NotImplemented. That includes bucket encryption, website, logging, notification, replication, accelerate, request payment, analytics, inventory, metrics, intelligent-tiering, PutBucketOwnershipControls, DeleteBucketOwnershipControls, GetObjectAttributes, RestoreObject, SelectObjectContent, and CreateSession.

Operation details​

FeatureBehavior
Server-side encryption headers501 NotImplemented, server-side encryption is not supported (<HEADER>); reissue the request without SSE headers. Conflicting SSE headers: 400 InvalidArgument.
Range on GetObjectSupported. Unsatisfiable: 416 InvalidRange.
If-Match, If-Unmodified-Since on GET, HEAD412 PreconditionFailed on mismatch.
If-None-Match, If-Modified-Since on GET, HEAD304 NotModified on match.
If-Match, If-None-Match on PutObject and CompleteMultipartUpload412 PreconditionFailed on mismatch.
If-Match, x-amz-if-match-size, x-amz-if-match-last-modified-time on DeleteObjectChecked.
partNumber on GetObject1 is accepted for a single-PUT object. For a multipart object the whole object is returned. Below 1, or above 1 on a single-PUT object: InvalidPart.
Content-MD5Checked on PutObject and UploadPart. Malformed: 400 InvalidDigest. Mismatch: 400 BadDigest.
ListObjectVersionsIgnores delimiter.
Lifecycle rulesSupports id, status, a prefix filter, expiration.days, abort_incomplete_multipart_upload.days_after_initiation, and noncurrent_version_expiration.noncurrent_days. Transitions, expired_object_delete_marker, and and, tag, or size filters: 501 NotImplemented.
Object Lock at CreateBucketTurns versioning on.
CopyObject from an access point or Outposts ARN501 NotImplemented.

Bucket names​

CreateBucket enforces these rules. A violation returns 400 InvalidBucketName.

RuleValue
Length3 to 63 characters
Charactersa-z, 0-9, -, .
First and last characterA lowercase letter or digit
Forbidden sequences.., -., .-
IPv4 formFour dot-separated numbers of 0 to 255 are refused
Prefixxn-- is refused

Every request path is also checked against the length, character, .., IP-address, and xn-- rules.

A new bucket gets a lifecycle rule, default-abort-incomplete-mpu-7d, that aborts multipart uploads incomplete after 7 days, and a public access block with all four settings on. CreateBucket with a LocationConstraint other than empty or the configured region returns 400 InvalidLocationConstraint. Re-creating a bucket you own, with no ACL headers and a default ACL, returns 200. Any other re-create returns 409 BucketAlreadyExists.

Limits​

LimitValueError
Object key length1024 bytes400 KeyTooLongError
Single PutObject body5 GiB, operator-tunable with MANTAD_MAX_BODY_BYTES400 EntityTooLarge
UploadPart bodySame as PutObject400 EntityTooLarge
Minimum part size5 MiB, except the last part, checked at CompleteMultipartUpload400 EntityTooSmall
Parts in CompleteMultipartUpload10,000400 InvalidRequest
Part numbering in CompleteMultipartUploadContiguous from 1, after duplicates collapse to the last entry400 InvalidPart
Body length on PutObject, UploadPartA SHA-256 or UNSIGNED-PAYLOAD request needs Content-Length or a body of known length. A streaming signed request needs x-amz-decoded-content-length. Transfer-Encoding: chunked alone does not waive either.411 MissingContentLength
Keys in DeleteObjects1000400 MalformedXML
List page size, ListParts, ListMultipartUploads1000Clamped
Lifecycle rules per bucket1000400 InvalidArgument
Object tags10 per object, 50 per bucket, key 128 characters, value 256 characters400 InvalidTag
XML request body20 MB400 MaxMessageLengthExceeded
Workspace quotaSet by the operator507 InsufficientStorage
Request rate per workspace, per mantad process1000 per second, burst 200503 SlowDown
Request rate across all workspaces, per mantad process20,000 per second, burst 4000503 SlowDown
Body idle timeout120 seconds

ETags​

ObjectETag
Single PUT, and each part"<MD5_HEX>" of the body
Multipart"<MD5_HEX>-<PART_COUNT>", the MD5 of the concatenated binary part MD5s

Error codes​

StatusCodes
304NotModified
400BadDigest, EntityTooLarge, EntityTooSmall, IncompleteBody, InvalidArgument, InvalidBucketName, InvalidDigest, InvalidLocationConstraint, InvalidPart, InvalidRequest, InvalidRetentionPeriod, InvalidTag, InvalidURI, KeyTooLongError, MalformedPOSTRequest, MalformedPolicy, MalformedXML, MaxMessageLengthExceeded, UnresolvableGrantByEmailAddress
403AccessDenied, InvalidAccessKeyId, InvalidDigest (Signature Version 2 header), RequestTimeTooSkewed, SignatureDoesNotMatch
404NoSuchBucket, NoSuchBucketPolicy, NoSuchCORSConfiguration, NoSuchKey, NoSuchLifecycleConfiguration, NoSuchObjectLockConfiguration, NoSuchPublicAccessBlockConfiguration, NoSuchTagSet, NoSuchUpload, ObjectLockConfigurationNotFoundError, OwnershipControlsNotFoundError
405MethodNotAllowed
409BucketAlreadyExists, BucketAlreadyOwnedByYou, BucketNotEmpty, InvalidBucketState
411MissingContentLength
412PreconditionFailed
416InvalidRange
500InternalError
501NotImplemented
503ServiceUnavailable, SlowDown
507InsufficientStorage

Error bodies are S3 XML with a <RequestId> element.

See also​