Skip to content

Blob Storage Management

Blob Storage Management allows you to configure where analysis images and results are stored. You can choose between Azure Blob Storage or S3-compatible storage (AWS S3, Hetzner Object Storage, MinIO, etc.) and manage authentication credentials.

Each tenant has its own blob storage configuration that determines where:

  • Input images are uploaded via presigned URLs
  • Analysis results (heatmaps, PDF reports) are stored

The Neuramancer API uses your configured storage credentials to generate presigned URLs for secure, direct file access without exposing your credentials to end users.

TypeDescriptionUse Cases
AzureAzure Blob StorageAzure-native deployments, enterprise Azure environments
S3S3-compatible storageAWS S3, Hetzner Object Storage, MinIO, DigitalOcean Spaces

sequenceDiagram
    participant C as Client
    participant API as Neuramancer API
    participant S as Blob Storage<br/>(Azure/S3)
    
    C->>API: POST /v1/analysis
    Note over API: Uses tenant's<br/>storageConfig
    API->>S: Generate presigned PUT URL
    S-->>API: Presigned URL (presignedUrlExpirySeconds expiry)
    API-->>C: Analysis + presigned URL
    C->>S: PUT image (direct upload)
    Note over API: Analysis processing
    API->>S: Upload heatmaps to storage
    C->>API: GET /v1/analysis?id=xxx
    API->>S: Generate presigned GET URL
    S-->>API: Presigned URL (presignedUrlExpirySeconds expiry)
    API-->>C: Analysis + result URLs
    C->>S: GET heatmap (direct download via presigned URL)

The API uses the tenant’s storage configuration to:

  1. Generate presigned upload URLs when analyses are created
  2. Upload processing results (heatmaps, reports) after inference completes
  3. Generate presigned download URLs for retrieving results
  4. Refresh presigned URLs automatically when you retrieve an analysis via GET request

Presigned URLs are publicly accessible but mathematically designed to be unguessable. They contain:

  • Cryptographic signatures based on storage credentials
  • Expiration timestamps
  • Random identifiers (analysis IDs)

While anyone with the URL can access the resource, the URL itself cannot be guessed or enumerated. The expiry time you configure balances security (shorter = better) with operational convenience (longer = fewer refresh requests).

To retrieve your tenant’s current blob storage configuration, use the following endpoint: GET /v1/tenant.

Data model: StorageConfig

Should the need arise to change your blob storage settings (e.g., rotate credentials), you can update the configuration using the following endpoint: PUT /v1/tenant.

In general, we recommend you to:

  • Regularly rotate storage credentials
  • Set appropriate presignedUrlExpirySeconds based on your application’s access patterns

Data model: StorageConfig


When uploading files to S3 presigned URLs directly from a browser (e.g. via fetch or XMLHttpRequest), the S3 bucket must have a CORS policy that allows your application’s origin. Without this, browsers will block the upload request.

Set the corsAllowedOrigins field in your tenant’s S3 configuration:

{
"storageType": "s3",
"storageConfig": {
"s3": {
"endpoint": "s3.example.com",
"port": 443,
"useSSL": true,
"bucketName": "my-bucket",
"region": "eu-central-1",
"accessKeyId": "...",
"secretAccessKey": "...",
"corsAllowedOrigins": [
"https://app.neuramancer.dev",
"https://app.neuramancer.de",
"http://app.neuramancer.localhost",
"https://app.neuramancer.localhost",
"https://app.example.com",
"http://localhost:3000"
]
}
}
}

The CORS policy is applied automatically:

  • On tenant update - whenever you PUT /v1/tenant with S3 config containing corsAllowedOrigins
  • On first presigned URL creation - when the bucket is first accessed (idempotent, cached per process)

If corsAllowedOrigins is not set in the tenant config, the following origins are applied by default:

  • https://app.neuramancer.dev
  • https://app.neuramancer.de
  • http://app.neuramancer.localhost
  • https://app.neuramancer.localhost

Set corsAllowedOrigins explicitly to override these defaults (e.g. to add your own domain or localhost port).