ClawBloc provides a REST API for programmatic file uploads to Arweave with optional Solana hash verification. Authenticate with an API key and start uploading.
All API endpoints require authentication. Pass your API key in one of two ways:
curl -H "x-api-key: cb_sk_your_key_here" \
https://clawbloc.com/api/v1/uploadscurl -H "Authorization: Bearer cb_sk_your_key_here" \
https://clawbloc.com/api/v1/uploadsGenerate API keys from your dashboard. Keys start with cb_sk_ and are shown only once at creation.
/api/v1/uploadUpload a file to Arweave. Optionally register the hash on Solana or mint an Agent NFT.
| Field | Type | Required | Description |
|---|---|---|---|
| file | binary | Yes | The file to upload (max 100 MB) |
| tier | string | No | raw | hash_registry | agent_nft (default: raw) |
| agent_name | string | No | Required for agent_nft tier |
| encrypted | boolean | No | Set to true if file was client-side encrypted (Basic/Pro only) |
| payment_tx | string | No | Solana TX signature for pay-per-upload |
curl -X POST https://clawbloc.com/api/v1/upload \
-H "x-api-key: cb_sk_your_key_here" \
-F "file=@./memory.json" \
-F "tier=hash_registry"{
"id": "a1b2c3d4-...",
"file_name": "memory.json",
"file_hash": "sha256:abc123...",
"file_size_bytes": 1234,
"tier": "hash_registry",
"status": "complete",
"arweave_tx_id": "AbCdEf...",
"arweave_url": "https://arweave.net/AbCdEf...",
"solana_hash_tx": "5xKm9...",
"nft_mint_address": null,
"encrypted": false,
"cost_lamports": 60000,
"payment_tx": null
}Note: cost_lamports is denominated in micro-USDC (6 decimals). Divide by 1,000,000 to get the USDC amount.
ClawBloc supports optional client-side AES-256-GCM encryption for uploads. Files are encrypted in your browser before leaving your device — the encryption key is derived from your wallet signature and is never stored anywhere.
ClawBloc Encryption Key v1curl -X POST https://clawbloc.com/api/v1/upload \
-H "x-api-key: cb_sk_your_key_here" \
-F "file=@./encrypted-data.bin" \
-F "tier=hash_registry" \
-F "encrypted=true"When using the API directly, you must encrypt the file yourself before uploading and pass encrypted=true. The dashboard handles this automatically.
| Property | Detail |
|---|---|
| Algorithm | AES-256-GCM |
| IV size | 12 bytes (96-bit), random per file |
| Key derivation | SHA-256(wallet_signature) |
| Key storage | None — derived on demand |
| Availability | Basic and Pro plans only |
Important: If you lose access to your wallet, encrypted files cannot be decrypted. There is no recovery mechanism — only the original signing wallet can derive the decryption key.
/api/v1/uploadsList your uploads with pagination and optional status filtering.
| Param | Default | Description |
|---|---|---|
| limit | 20 | Results per page (max 100) |
| offset | 0 | Number of results to skip |
| status | all | Filter: complete, failed, pending, uploading, processing |
curl "https://clawbloc.com/api/v1/uploads?limit=10&status=complete" \
-H "x-api-key: cb_sk_your_key_here"{
"data": [
{
"id": "a1b2c3d4-...",
"file_name": "memory.json",
"file_hash": "sha256:abc123...",
"file_size_bytes": 1234,
"tier": "raw",
"status": "complete",
"arweave_tx_id": "AbCdEf...",
"arweave_url": "https://arweave.net/AbCdEf...",
"solana_hash_tx": null,
"nft_mint_address": null,
"cost_lamports": 60000,
"created_at": "2026-03-01T00:00:00Z"
}
],
"total": 42,
"limit": 10,
"offset": 0
}/api/v1/uploads/:idGet full details for a single upload by its ID.
curl https://clawbloc.com/api/v1/uploads/a1b2c3d4-... \
-H "x-api-key: cb_sk_your_key_here"{
"data": {
"id": "a1b2c3d4-...",
"file_name": "memory.json",
"file_hash": "sha256:abc123...",
"file_size_bytes": 1234,
"mime_type": "application/json",
"tier": "hash_registry",
"status": "complete",
"arweave_tx_id": "AbCdEf...",
"arweave_url": "https://arweave.net/AbCdEf...",
"solana_hash_tx": "5xKm9...",
"nft_mint_address": null,
"cost_lamports": 60000,
"payment_tx": null,
"error_message": null,
"created_at": "2026-03-01T00:00:00Z",
"updated_at": "2026-03-01T00:00:05Z"
}
}/api/v1/uploads?status=failedDelete all failed upload records for your account.
curl -X DELETE "https://clawbloc.com/api/v1/uploads?status=failed" \
-H "x-api-key: cb_sk_your_key_here"{
"deleted": 4,
"message": "Deleted 4 failed upload(s)"
}| Status | Meaning |
|---|---|
| 400 | Bad request — missing or invalid parameters |
| 401 | Unauthorized — invalid or missing API key |
| 402 | Payment required — upload payment not confirmed |
| 403 | Forbidden — storage limit exceeded or tier not allowed |
| 404 | Not found — upload does not exist |
| 409 | Conflict — duplicate payment transaction |
| 413 | Payload too large — file exceeds 100 MB |
| 429 | Too many requests — rate limit exceeded (see Retry-After header) |
| 500 | Internal server error |
| Plan | Requests/min | Storage | API Keys | Upload Tiers |
|---|---|---|---|---|
| Free | 10 | 50 MB | 1 | raw |
| Basic (5 USDC/mo) | 60 | 500 MB | 5 | raw, hash_registry |
| Pro (50 USDC/mo) | 1,000 | 50 GB | Unlimited | raw, hash_registry, agent_nft |
Max file size: 100 MB per upload for all plans.
const fs = require('fs');
const API_KEY = 'cb_sk_your_key_here';
const BASE_URL = 'https://clawbloc.com/api/v1';
// Upload a file
async function upload(filePath, tier = 'raw') {
const form = new FormData();
form.append('file', new Blob([fs.readFileSync(filePath)]));
form.append('tier', tier);
const res = await fetch(`${BASE_URL}/upload`, {
method: 'POST',
headers: { 'x-api-key': API_KEY },
body: form,
});
return res.json();
}
// List uploads
async function listUploads(limit = 20) {
const res = await fetch(
`${BASE_URL}/uploads?limit=${limit}`,
{ headers: { 'x-api-key': API_KEY } }
);
return res.json();
}
// Usage
const result = await upload('./memory.json', 'hash_registry');
console.log('Arweave URL:', result.arweave_url);
console.log('Solana TX:', result.solana_hash_tx);import requests
API_KEY = "cb_sk_your_key_here"
BASE_URL = "https://clawbloc.com/api/v1"
HEADERS = {"x-api-key": API_KEY}
# Upload a file
def upload(file_path, tier="raw"):
with open(file_path, "rb") as f:
res = requests.post(
f"{BASE_URL}/upload",
headers=HEADERS,
files={"file": f},
data={"tier": tier},
)
return res.json()
# List uploads
def list_uploads(limit=20, status=None):
params = {"limit": limit}
if status:
params["status"] = status
res = requests.get(
f"{BASE_URL}/uploads",
headers=HEADERS,
params=params,
)
return res.json()
# Usage
result = upload("./memory.json", tier="hash_registry")
print("Arweave URL:", result.get("arweave_url"))
print("Solana TX:", result.get("solana_hash_tx"))Need help? hello@clawbloc.com