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 example response-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