Get Started with the S3 API
IronShard speaks the Amazon S3 API. Any tool that talks to S3, including the AWS CLI, boto3, the JavaScript SDK, s3cmd, and Cyberduck, works against it with a changed endpoint and no client library of ours. What differs is underneath: every object is encrypted, erasure-coded into fragments, and distributed across the providers and locations you allow, so no single provider holds a complete object.
This page goes from nothing to a stored object using the AWS CLI, then shows the same sequence in Python and JavaScript.
What You Need
- Endpoint:
https://s3.ironshard.ai - Access key: An access key ID and secret access key, created in the console.
- Geo-fence: Defines the regions an object's fragments may be placed in. Leave it unset for now; your account's default is applied.
Walkthrough
1. Create an Access Key
In the console, open S3 Access Keys → New API Key. Grant the key permission to create buckets, since step 4 needs it.
The secret access key is shown once, when the key is created. Copy it into your secret manager before closing the dialog. A lost secret cannot be recovered; you create a replacement key and delete the old one.
Name the key for the workload. Name it for the service or job that will use it, not for the person creating it. One key per consumer keeps request logs legible and lets you retire a single workload without rotating credentials everywhere else.
2. Install AWS CLI v2
Confirm the major version is 2:
aws --version
The output starts with aws-cli/2.. Version 1 does not support the endpoint_url profile setting used below.
3. Configure a Profile
Add a named profile so IronShard sits alongside any AWS profiles you already have. If these files exist, append to them.
~/.aws/config:
[profile ironshard]
endpoint_url = https://s3.ironshard.ai
signature_version = s3v4
s3 =
addressing_style = path
multipart_threshold = 128MB
multipart_chunksize = 128MB
s3api =
addressing_style = path
~/.aws/credentials:
[ironshard]
aws_access_key_id = <YOUR_ACCESS_KEY_ID>
aws_secret_access_key = <YOUR_SECRET_ACCESS_KEY>
Two of these settings matter more than they look:
- Path addressing. Buckets are addressed as
https://s3.ironshard.ai/BUCKET/OBJECT, not as subdomains. - 128 MB parts. This matches the chunk size IronShard uses internally. Other values force re-chunking on our side and measurably slow both uploads and downloads.
4. Create a Bucket
aws s3 mb s3://agent-scratch-7fk2qa --profile ironshard --region ""
make_bucket: agent-scratch-7fk2qa
Bucket names are globally unique across the platform, so the example carries a random suffix.
The --region flag is where a geo-fence would go. Leave it as an empty string and your default is chosen. This is the only request where region means anything. Everywhere else, set it to any value.
5. Upload an Object
aws s3 cp ./report.parquet s3://agent-scratch-7fk2qa/ --profile ironshard
upload: ./report.parquet to s3://agent-scratch-7fk2qa/report.parquet
6. List the Bucket
aws s3 ls s3://agent-scratch-7fk2qa --profile ironshard
2026-09-22 14:22:10 4823104 report.parquet
7. Download It Back
aws s3 cp s3://agent-scratch-7fk2qa/report.parquet ./restored.parquet --profile ironshard
Byte-range downloads are supported, so a client can fetch part of an object without reading the whole thing.
8. Delete It
aws s3 rm s3://agent-scratch-7fk2qa/report.parquet --profile ironshard
Versioning is always on. Every bucket is versioned and versioning cannot be switched off. A delete writes a delete marker rather than removing data. Earlier versions stay until you delete them explicitly by version ID. Plan for this when you estimate stored volume, and when an agent's cleanup step "frees" space.
The Same Thing in Python
import os
import boto3
from boto3.s3.transfer import TransferConfig
from botocore.config import Config
s3 = boto3.client(
"s3",
endpoint_url="https://s3.ironshard.ai",
region_name="us-east-1", # required for signing; ignored by IronShard
aws_access_key_id=os.environ["IRONSHARD_ACCESS_KEY_ID"],
aws_secret_access_key=os.environ["IRONSHARD_SECRET_ACCESS_KEY"],
config=Config(
signature_version="s3v4",
s3={"addressing_style": "path"},
),
)
# Leave LocationConstraint out; the default geo-fence is applied.
s3.create_bucket(Bucket="agent-scratch-7fk2qa")
transfer = TransferConfig(
multipart_threshold=128 * 1024 * 1024,
multipart_chunksize=128 * 1024 * 1024,
)
s3.upload_file(
"report.parquet", "agent-scratch-7fk2qa", "report.parquet",
Config=transfer,
)
The Same Thing in JavaScript
import { S3Client, CreateBucketCommand } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { createReadStream } from "node:fs";
const s3 = new S3Client({
endpoint: "https://s3.ironshard.ai",
region: "us-east-1", // required for signing; ignored by IronShard
forcePathStyle: true,
credentials: {
accessKeyId: process.env.IRONSHARD_ACCESS_KEY_ID,
secretAccessKey: process.env.IRONSHARD_SECRET_ACCESS_KEY,
},
});
// Leave CreateBucketConfiguration out; the default geo-fence is applied.
await s3.send(new CreateBucketCommand({ Bucket: "agent-scratch-7fk2qa" }));
await new Upload({
client: s3,
partSize: 128 * 1024 * 1024,
params: {
Bucket: "agent-scratch-7fk2qa",
Key: "report.parquet",
Body: createReadStream("report.parquet"),
},
}).done();
What Is and Isn't Supported Today
Full object and bucket lifecycle, multipart upload, versioning, byte-range reads, and user-defined object metadata all work. Three things to know before you design around them:
- Overriding response headers on
GetObject(for exampleresponse-cache-control) is not supported. - Object tagging is not yet available; user-defined object metadata is.
- There is no CORS configuration, so browser-based clients cannot talk to the endpoint directly. Use a server, an SDK, or the console.
Next Steps
- Agent Buckets: let an autonomous agent create and operate a bucket over MCP, with no account.
- Erasure Coding and Distribution: how objects are erasure-coded and distributed across providers, and geo-fencing.
