Skip to content

Compatibilidade S3

Use o AWS SDK para enviar, baixar e gerenciar arquivos no IPFS Ninja com o mesmo código que você usa para o Amazon S3.

Endpoint

https://s3.ipfs.ninja

Credenciais

A API S3 usa sua chave de API do IPFS Ninja para autenticação. Sua chave de API funciona tanto como access key quanto como secret key.

Como obter suas credenciais

  1. Acesse Dashboard > API Keys
  2. Clique em Create API key e dê um nome a ela (ex.: "S3 access")
  3. Copie a chave completa imediatamente — ela é exibida apenas uma vez e não pode ser recuperada depois

Sua chave se parece com isto:

bws_628bba35e9e0079d9ff9c392b1b55a7b
├──────────┘└──────────────────────────┘
 prefix (12 chars)    rest of key

Mapeamento para credenciais AWS

Parâmetro AWSValorExemplo
accessKeyIdOs primeiros 12 caracteres da sua chave de APIbws_628bba35
secretAccessKeyA chave de API completa (todos os 36 caracteres)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionSempre us-east-1us-east-1

WARNING

A chave de API completa só é exibida uma vez, no momento em que você a cria. Se você perdê-la, exclua a chave e crie uma nova na página de API Keys.

Início Rápido

javascript
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: "https://s3.ipfs.ninja",
  credentials: {
    accessKeyId: "bws_628bba35",
    secretAccessKey: "bws_628bba35e9e0079d9ff9c392b1b55a7b"
  },
  region: "us-east-1",
  forcePathStyle: true
});

// Upload a file
const put = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "hello.json",
  Body: JSON.stringify({ hello: "IPFS" }),
  ContentType: "application/json"
}));

console.log("CID:", put.Metadata?.cid);
// CID: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

Buckets = Pastas

Buckets S3 correspondem às suas pastas no IPFS Ninja. Quando você envia um arquivo para um bucket, ele é armazenado na pasta correspondente. Quando você lista objetos em um bucket, você vê os arquivos daquela pasta.

Operação S3Equivalente no IPFS Ninja
CreateBucketCriar uma nova pasta
ListBucketsListar suas pastas
DeleteBucketExcluir uma pasta e todos os arquivos nela
PutObject no bucketEnviar arquivo para a pasta
ListObjectsV2 no bucketListar arquivos na pasta
javascript
import { ListBucketsCommand, CreateBucketCommand, PutObjectCommand } from "@aws-sdk/client-s3";

// Create a bucket (= create a folder)
await s3.send(new CreateBucketCommand({ Bucket: "nft-metadata" }));

// Upload a file into the folder
await s3.send(new PutObjectCommand({
  Bucket: "nft-metadata",      // ← folder name
  Key: "token-42.json",        // ← filename within the folder
  Body: JSON.stringify({ name: "My NFT #42" })
}));

// List buckets (= list your folders)
const { Buckets } = await s3.send(new ListBucketsCommand({}));
console.log(Buckets);
// [{ Name: "nft-metadata", CreationDate: "2026-04-13T..." }]

TIP

As pastas criadas pela API S3 são as mesmas pastas visíveis no seu Dashboard. Você pode organizar arquivos tanto pela API S3, quanto pela API REST, ou pela interface web — todas compartilham o mesmo sistema de pastas.

INFO

Diferente do Amazon S3, as pastas do IPFS Ninja são planas por padrão. Para criar estruturas aninhadas, use os endpoints de pastas da API REST com parentFolderId. Pela API S3, use prefixos de chave (ex.: images/photo.png) para organizar dentro de uma pasta.

Nomes de bucket são globalmente únicos

Nomes de bucket vivem em um namespace global entre todos os clientes, seguindo a mesma semântica do AWS S3. Isso significa que:

  • O primeiro usuário a criar um bucket com um determinado nome reivindica esse nome globalmente.
  • Chamadas posteriores de CreateBucket com o mesmo nome, vindas de qualquer conta, retornam BucketAlreadyExists (409).
  • Se você tentar recriar seu próprio bucket, recebe BucketAlreadyOwnedByYou (409).
  • O nome da sua pasta no painel é por conta e pode continuar sendo qualquer coisa — apenas o nome do bucket visível via S3 passa pelo namespace global.

Se o nome que você quer já está em uso, escolha um com escopo diferente (myapp-photos-2026, acme-nft-metadata) — a mesma convenção que você usaria no Amazon S3.

Operações Suportadas

PutObject

Envia um arquivo para o IPFS. O arquivo é fixado, verificado quanto à segurança, e o CID é retornado nos cabeçalhos ETag e x-amz-meta-cid.

Para importar um arquivo CAR em vez de um arquivo normal, adicione o cabeçalho de metadados x-amz-meta-import: car. Veja Importação de CAR para detalhes.

javascript
import { PutObjectCommand } from "@aws-sdk/client-s3";
import fs from "fs";

const result = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "photo.png",
  Body: fs.readFileSync("photo.png"),
  ContentType: "image/png"
}));

console.log("CID:", result.ETag);
bash
# curl equivalent
curl -X PUT "https://s3.ipfs.ninja/my-project/photo.png" \
  --data-binary @photo.png \
  -H "Content-Type: image/png" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  --user "bws_628bba35:bws_628bba35e9e0079d9ff9c392b1b55a7b"

GetObject

Baixa um arquivo pela sua chave (nome do arquivo) ou CID.

javascript
import { GetObjectCommand } from "@aws-sdk/client-s3";

const result = await s3.send(new GetObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

const body = await result.Body.transformToByteArray();
console.log("Size:", body.length);
console.log("CID:", result.Metadata?.cid);

HeadObject

Obtém os metadados do arquivo sem baixar o conteúdo.

javascript
import { HeadObjectCommand } from "@aws-sdk/client-s3";

const head = await s3.send(new HeadObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

console.log("Size:", head.ContentLength);
console.log("Type:", head.ContentType);
console.log("CID:", head.Metadata?.cid);

DeleteObject

Remove a fixação de um arquivo do IPFS e o exclui da sua conta.

javascript
import { DeleteObjectCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

ListObjectsV2

Lista arquivos em um bucket com filtragem opcional por prefixo e paginação.

javascript
import { ListObjectsV2Command } from "@aws-sdk/client-s3";

const list = await s3.send(new ListObjectsV2Command({
  Bucket: "my-project",
  Prefix: "images/",
  MaxKeys: 100
}));

for (const obj of list.Contents ?? []) {
  console.log(obj.Key, obj.Size, obj.ETag); // ETag = CID
}

Multipart Upload

Envie arquivos grandes (até 5 GB) usando upload multipart. O AWS SDK cuida disso automaticamente:

javascript
import { Upload } from "@aws-sdk/lib-storage";
import fs from "fs";

const upload = new Upload({
  client: s3,
  params: {
    Bucket: "my-project",
    Key: "large-dataset.tar.gz",
    Body: fs.createReadStream("large-dataset.tar.gz"),
    ContentType: "application/gzip"
  },
  partSize: 10 * 1024 * 1024, // 10 MB per part
});

upload.on("httpUploadProgress", (progress) => {
  console.log(`Uploaded ${progress.loaded} of ${progress.total} bytes`);
});

const result = await upload.done();
console.log("CID:", result.ETag);

Ou controle as partes manualmente:

javascript
import {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand
} from "@aws-sdk/client-s3";

// 1. Start
const { UploadId } = await s3.send(new CreateMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin"
}));

// 2. Upload parts
const part1 = await s3.send(new UploadPartCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  PartNumber: 1,
  Body: chunk1
}));

// 3. Complete
const result = await s3.send(new CompleteMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  MultipartUpload: {
    Parts: [{ PartNumber: 1, ETag: part1.ETag }]
  }
}));

Exemplo em Python

python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.ipfs.ninja",
    aws_access_key_id="bws_628bba35",
    aws_secret_access_key="bws_628bba35e9e0079d9ff9c392b1b55a7b",
    region_name="us-east-1"
)

# Upload
s3.put_object(
    Bucket="my-project",
    Key="data.json",
    Body=b'{"hello": "IPFS"}',
    ContentType="application/json"
)

# List files
response = s3.list_objects_v2(Bucket="my-project")
for obj in response.get("Contents", []):
    print(obj["Key"], obj["Size"])

# Download
result = s3.get_object(Bucket="my-project", Key="data.json")
print(result["Body"].read())

Exemplo em Go

go
package main

import (
    "context"
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    client := s3.New(s3.Options{
        BaseEndpoint: aws.String("https://s3.ipfs.ninja"),
        Region:       "us-east-1",
        Credentials:  credentials.NewStaticCredentialsProvider("bws_628bba35", "bws_628bba35e9e0...", ""),
        UsePathStyle: true,
    })

    _, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket:      aws.String("my-project"),
        Key:         aws.String("hello.txt"),
        Body:        strings.NewReader("Hello, IPFS!"),
        ContentType: aws.String("text/plain"),
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Uploaded!")
}

Configurar CORS (acesso via SDK no navegador)

Se você está chamando a API S3 diretamente do JavaScript do navegador (SPA, app de carteira, ferramenta de painel), primeiro é preciso configurar o CORS no bucket. Caso contrário, os navegadores bloqueiam o preflight e seus uploads falham com No 'Access-Control-Allow-Origin' header is present.

Mesmo formato do AWS S3 — subrecursos PutBucketCors / GetBucketCors / DeleteBucketCors:

PutBucketCors

javascript
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new PutBucketCorsCommand({
  Bucket: "my-bucket",
  CORSConfiguration: {
    CORSRules: [{
      AllowedOrigins: ["http://localhost:3000", "https://myapp.com"],
      AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE"],
      AllowedHeaders: ["*"],
      ExposeHeaders: ["ETag", "x-amz-meta-cid", "x-amz-request-id"],
      MaxAgeSeconds: 3600,
    }],
  },
}));

GetBucketCors

javascript
import { GetBucketCorsCommand } from "@aws-sdk/client-s3";

const { CORSRules } = await s3.send(new GetBucketCorsCommand({ Bucket: "my-bucket" }));
console.log(CORSRules);

DeleteBucketCors

javascript
import { DeleteBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteBucketCorsCommand({ Bucket: "my-bucket" }));

Limites e padrões

  • Até 5 regras por bucket (a especificação permite 100; nós limitamos a 5 para manter a resposta do preflight do navegador compacta).
  • Configuração total limitada a 64 KB serializados.
  • Se nenhuma configuração de CORS estiver definida, os preflights do navegador são rejeitados — seguindo a postura padrão do AWS S3. Configure regras explícitas para as origens a partir das quais você realmente serve conteúdo.

Nota de segurança na prática

CORS é uma camada de conveniência do lado do navegador, não uma barreira de segurança. Toda chamada à API S3 ainda exige uma assinatura SigV4 válida computada a partir da sua chave de API — uma configuração de CORS permissiva não permite que qualquer pessoa use seu bucket sem essa credencial. O que o CORS realmente evita: uma origem não intencional (ex.: uma cópia desatualizada do seu app em dev.myapp.com) enviando requisições assinadas a partir de um contexto de navegador.

Alternativa pelo painel

A página Arquivos tem uma opção S3 CORS no menu de ações de cada pasta. Mesmo armazenamento por baixo dos panos; se você não quiser escrever código para PutBucketCors, configure por lá.

Diferenças em relação ao Amazon S3

RecursoAmazon S3IPFS Ninja S3
Modelo de armazenamentoObjetos mutáveisEndereçado por conteúdo (CIDs imutáveis)
Comportamento de sobrescritaSubstitui o objeto no lugarCria um novo CID; o CID antigo continua acessível
VersionamentoSuportadoNão suportado (use CIDs para versionamento)
Criptografia no servidorSuportadaNão suportada (o conteúdo está no IPFS)
Políticas de ciclo de vidaSuportadasNão suportadas
Políticas de bucket / ACLsSuportadasUse os modos de acesso do gateway
URLs pré-assinadasSuportadasUse os tokens de upload assinados
Tamanho máximo do objeto5 TB5 GB (multipart), 100 MB (PUT único)
RegiõesMultirregiãoApenas us-east-1
Valor do ETagHash MD5CID do IPFS
Cabeçalhos extrasS3 padrãox-amz-meta-cid (CID do IPFS)
Formato do CIDN/ACIDv1 moderno (bafy…) para novos uploads; Qm… legado continua válido como entrada
Namespace de bucketGlobal (em toda a AWS)Global (entre todas as contas do IPFS Ninja) — mesma semântica
CORSPutBucketCors suportadoPutBucketCors suportado (limite de 5 regras)

Migrando do Amazon S3

Substitua a configuração do seu cliente S3:

diff
 const s3 = new S3Client({
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "AKIA...",
-    secretAccessKey: "wJalrX..."
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
+  forcePathStyle: true
 });

Suas chamadas existentes de PutObject, GetObject, ListObjectsV2 e DeleteObject funcionam sem alterações.

Migrando do Filebase

Substitua a URL do endpoint:

diff
 const s3 = new S3Client({
-  endpoint: "https://s3.filebase.com",
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "FILEBASE_KEY",
-    secretAccessKey: "FILEBASE_SECRET"
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
   forcePathStyle: true
 });