Skip to main content
POST
/
storage
/
boto
Storage — Boto Credentials
curl --request POST \
  --url https://api.minerva.io/storage/boto \
  --header 'x-api-key: <api-key>'
{
  "credentials": {
    "aws_region": "us-east-1",
    "aws_key_id": "ASIAIOSFODNN7EXAMPLE",
    "aws_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "aws_session_token": "FwoGZXIvYXdzEJr...truncated",
    "aws_session_expiration": "2026-06-29T16:30:00+00:00"
  },
  "bucket_info": {
    "name": "prod-minerva-client-acme",
    "prefix": "acme/",
    "uri": "s3://prod-minerva-client-acme/acme/"
  }
}

Quick Answer

How do I upload or download files to/from Minerva? Call this endpoint to receive short-lived AWS credentials scoped to your org’s storage area, then use any AWS SDK (boto3, AWS CLI, etc.) to read/write objects.Common questions this endpoint answers:
  • How do I send large files into Minerva?
  • How do I retrieve exported / batch results?
  • How do I authenticate to Minerva’s S3 storage?
  • How long are storage credentials valid?
  • Can I use the AWS CLI / boto3 directly?
What you need: A valid Minerva API key (x-api-key).What you get back: Temporary AWS credentials (access key, secret, session token, expiration) plus the S3 bucket name and your org’s prefix.

Overview

This endpoint mints short-lived AWS STS credentials scoped to your org’s directory inside the Minerva client storage bucket. Use them with boto3, the AWS CLI, or any AWS SDK to upload files for processing and download exports. Each org has a dedicated bucket; credentials are additionally scoped via session policy to {your_org}/* only, so other orgs’ data is unreachable even if a key were misused. By convention the org directory has two subfolders:
  • Incoming/ — files you send in (resolve/enrich batches, segment uploads, …).
  • Outgoing/ — files placed for you to read (exports, batch results, …).
The Python SDK wraps this endpoint behind mc.storageupload, download, list, plus bulk helpers — and handles credential refresh automatically. See the Storage SDK guide. The boto endpoint is documented here for AWS-SDK / CLI integrations and other languages.

Request

Headers

x-api-key
string
required
Your Minerva API key.

Request Body

No body. Send POST with an empty body (or {}).

Response

Response Structure

credentials
object
Temporary AWS credentials scoped to your org’s storage area.
bucket_info
object
Bucket name + prefix to scope your AWS-SDK calls to.

credentials

aws_region
string
AWS region the bucket lives in. Always us-east-1 today.
aws_key_id
string
Temporary access key ID.
aws_secret_access_key
string
Temporary secret access key.
aws_session_token
string
Temporary session token. Required alongside the access key / secret for STS credentials.
aws_session_expiration
string
ISO 8601 timestamp at which the credentials expire. Typically 1 hour from issue. Refresh by calling this endpoint again before expiry.

bucket_info

name
string
S3 bucket name. Pass this as the Bucket= parameter on boto3 calls.
prefix
string
Your org’s directory inside the bucket — every key you read or write must start with this prefix. Looks like <your-minerva-org-id>/.
uri
string
Convenience s3://{name}/{prefix} URI. Useful as a base for the AWS CLI (aws s3 cp ./local.csv $URI/Incoming/local.csv).
{
  "credentials": {
    "aws_region": "us-east-1",
    "aws_key_id": "ASIAIOSFODNN7EXAMPLE",
    "aws_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "aws_session_token": "FwoGZXIvYXdzEJr...truncated",
    "aws_session_expiration": "2026-06-29T16:30:00+00:00"
  },
  "bucket_info": {
    "name": "prod-minerva-client-acme",
    "prefix": "acme/",
    "uri": "s3://prod-minerva-client-acme/acme/"
  }
}

Error Responses

  • 401 — Unauthorized: invalid or missing API key.
  • 403 — Forbidden: API key isn’t entitled to storage, or org identity couldn’t be resolved.
  • 500 — Internal Server Error: credential provisioning failed.

Example — boto3

import boto3
import requests

resp = requests.post(
    "https://api.minerva.io/storage/boto",
    headers={"x-api-key": "<your-api-key>"},
).json()

creds = resp["credentials"]
bucket = resp["bucket_info"]["name"]
prefix = resp["bucket_info"]["prefix"]

s3 = boto3.client(
    "s3",
    aws_access_key_id=creds["aws_key_id"],
    aws_secret_access_key=creds["aws_secret_access_key"],
    aws_session_token=creds["aws_session_token"],
    region_name=creds["aws_region"],
)

# Upload into your Incoming/ folder
s3.upload_file("local.csv", bucket, f"{prefix}Incoming/local.csv")

# List what's waiting in Outgoing/
for obj in s3.list_objects_v2(Bucket=bucket, Prefix=f"{prefix}Outgoing/").get("Contents", []):
    print(obj["Key"], obj["Size"])

Example — AWS CLI

Export the credentials and use the AWS CLI like normal:
RESPONSE=$(curl -s -X POST https://api.minerva.io/storage/boto \
  -H "x-api-key: $MINERVA_API_KEY")

export AWS_ACCESS_KEY_ID=$(echo "$RESPONSE" | jq -r '.credentials.aws_key_id')
export AWS_SECRET_ACCESS_KEY=$(echo "$RESPONSE" | jq -r '.credentials.aws_secret_access_key')
export AWS_SESSION_TOKEN=$(echo "$RESPONSE" | jq -r '.credentials.aws_session_token')
export AWS_DEFAULT_REGION=us-east-1

URI=$(echo "$RESPONSE" | jq -r '.bucket_info.uri')

aws s3 cp ./local.csv "${URI}Incoming/local.csv"
aws s3 ls "${URI}Outgoing/"

Notes

  • Credential lifetime: typically 1 hour. Refresh by calling the endpoint again before aws_session_expiration.
  • Scope: credentials are limited to s3:GetObject / s3:PutObject / s3:DeleteObject on {prefix}* and s3:ListBucket filtered to that same prefix. Other prefixes and operations fail closed.
  • Caching: the Python SDK caches the credentials in-process and auto-refreshes them near expiry. If you call this endpoint directly, implement the same pattern in your own client (don’t call it per request — keep a single set of creds and refresh ahead of expiry).
  • Region: bucket lives in us-east-1 today.
  • Convention: use Incoming/ for client-to-Minerva transfers and read from Outgoing/ for Minerva-to-client transfers. The session policy permits writes to both, but downstream pipelines watch Incoming/.