# DIEMshare Agent API

Bulk AI image and video generation powered by idle Venice DIEM capacity. Buyer price: **$0.50 per DIEM** (50% discount vs direct Venice).

Base URL: your DIEMshare instance (e.g. `https://diemshare.example.com`)

## Authentication

### Option 1: x402 (No Account Required)

AI agents can pay per request using the [x402 protocol](https://github.com/coinbase/x402). No signup, no deposit, no API keys.

1. `POST /api/jobs` with no auth headers
2. Server responds **402 Payment Required** with a `PAYMENT-REQUIRED` header (base64 JSON containing price, chain, token, recipient)
3. Agent signs a USDC transfer authorization (EIP-3009) for the quoted amount
4. Agent retries the same request with the `PAYMENT-SIGNATURE` header
5. Server verifies, runs the job, settles the payment on-chain
6. Response includes `PAYMENT-RESPONSE` header with settlement tx hash
7. Response body includes `sessionToken` — use as `Authorization: Bearer <token>` to poll status and download results

x402 payments use USDC on Base. Agent SDKs that support x402 handle steps 2-4 automatically.

**x402 response example:**
```json
{
  "jobId": "abc123",
  "estimatedCost": 0.025,
  "sessionToken": "a1b2c3d4e5f6..."
}
```

Use the session token for all subsequent requests:
```
Authorization: Bearer a1b2c3d4e5f6...
```

The token is valid for 7 days and grants access to all jobs created by your wallet address. You can also authenticate via SIWE (Sign-In with Ethereum) with the same wallet as an alternative.

### Option 2: Session-Based

```
POST /api/auth/login
Content-Type: application/json

{ "username": "your_user", "password": "your_password" }
```

Returns a session cookie (7-day expiry). Include the cookie on all subsequent requests. Accounts are auto-created on first login.

Before submitting jobs, deposit USDC to your account via the escrow contract (see the web UI at `/generate/deposit`).

## Submit a Job

```
POST /api/jobs
Content-Type: application/json
Cookie: session=... (or use x402)
```

### Image Job

```json
{
  "job_type": "image",
  "defaults": {
    "model": "seedream-v4",
    "width": 1024,
    "height": 1024
  },
  "images": [
    { "prompt": "a cat riding a rocket through space" },
    { "prompt": "sunset over mountains", "model": "chroma", "width": 1280, "height": 720 }
  ]
}
```

**Image parameters:**

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `prompt` | yes | — | Text description of the image |
| `model` | no | `seedream-v4` | Model ID (see Available Models below) |
| `width` | no | 1024 | Image width in pixels (256-2048) |
| `height` | no | 1024 | Image height in pixels (256-2048) |
| `params` | no | — | Optional object passed through to generation engine |

Per-image fields override `defaults`. Only `prompt` is required per image.

### Video Job

```json
{
  "job_type": "video",
  "defaults": {
    "model": "grok-imagine-text-to-video",
    "duration": 5,
    "resolution": "720p",
    "aspect_ratio": "16:9"
  },
  "images": [
    { "prompt": "a wave crashing on a beach at golden hour" }
  ]
}
```

**Video parameters:**

| Field | Required | Default | Values |
|-------|----------|---------|--------|
| `prompt` | yes | — | Text description |
| `model` | no | `grok-imagine-text-to-video` | Currently only one video model |
| `duration` | no | 5 | `5`, `10`, or `15` (seconds) |
| `resolution` | no | `720p` | `480p`, `720p` |
| `aspect_ratio` | no | `16:9` | `16:9`, `4:3`, `3:2`, `1:1`, `2:3`, `3:4`, `9:16` |

### Limits

- 1-500 items per job (the `images` array)
- Per-user: max 10 active jobs, max 1000 active items
- Rate limit: 5 job submissions per 60 seconds

### Response (201 Created)

```json
{
  "jobId": "abc123",
  "estimatedCost": 12.50
}
```

## Available Models

Image models are dynamic. Query the current list:

```
GET /api/models
```

Response:
```json
{
  "image": [
    { "id": "seedream-v4", "name": "SeedreamV4.5", "max_resolution": "1280px", "price_diem": null, "tier": "standard" },
    { "id": "chroma", "name": "Chroma", "max_resolution": "1280px", "price_diem": null, "tier": "standard" }
  ],
  "video": [
    { "id": "grok-imagine-text-to-video", "durations": [5, 10, 15], "resolutions": ["480p", "720p"], "aspect_ratios": ["16:9", "4:3", "3:2", "1:1", "2:3", "3:4", "9:16"] }
  ]
}
```

When `price_diem` is `null`, the default platform rate applies (currently 0.05 DIEM per image).

## Get a Price Quote

Get the cost of a job without submitting it:

```
POST /api/jobs/quote
Content-Type: application/json

{ "images": [{"prompt": "test"}], "defaults": {"model": "seedream-v4"} }
```

Response:
```json
{
  "estimatedCost": 0.025,
  "itemCount": 1,
  "costPerItem": 0.025,
  "jobType": "image",
  "currency": "USDC"
}
```

No authentication required.

## x402 Discovery

Agents can discover x402-protected resources programmatically:

```
GET /.well-known/x402
```

Response:
```json
{
  "resources": [{
    "path": "/api/jobs",
    "method": "POST",
    "scheme": "exact",
    "network": "base-sepolia",
    "token": "USDC",
    "docs": "/docs/agent-api.md",
    "quote": "/api/jobs/quote",
    "models": "/api/models"
  }]
}
```

## Poll Job Status

```
GET /api/jobs/{jobId}
Authorization: Bearer <sessionToken>
```

**Response:**

```json
{
  "job": {
    "id": "abc123",
    "status": "processing",
    "job_type": "image",
    "total_images": 10,
    "completed_images": 4,
    "succeeded_images": 3,
    "failed_images": 1,
    "estimated_cost": 0.25,
    "actual_cost": null,
    "created_at": "2026-03-19T12:00:00.000Z"
  },
  "images": [
    {
      "id": "img_001",
      "index_in_job": 0,
      "status": "completed",
      "prompt": "a cat riding a rocket",
      "model": "seedream-v4",
      "width": 1024,
      "height": 1024,
      "file_size": 1048576,
      "completed_at": "2026-03-19T12:01:30.000Z"
    }
  ]
}
```

**Job statuses:** `queued`, `processing`, `completed`, `failed`, `cancelled`

**Item statuses:** `pending`, `processing`, `completed`, `failed`, `dead_letter`

## Download Results

```
GET /api/jobs/{jobId}/images/{imageId}
Authorization: Bearer <sessionToken>
```

Returns the image binary (`Content-Type: image/png`). Only available for items with `status: "completed"`. Files are retained for 24 hours.

For video jobs, replace `images` with `videos` in the URL and response field names.

## Error Codes

| Status | Meaning |
|--------|---------|
| 400 | Invalid request (bad model, missing prompt, invalid dimensions) |
| 401 | Not authenticated |
| 402 | Payment required (x402 flow — includes price in header) |
| 404 | Job or image not found |
| 410 | Image file expired (past retention window) |
| 429 | Rate limit or queue limit exceeded (check `Retry-After` header) |
| 503 | Service temporarily unavailable — queue full or system degraded (check `Retry-After` header) |

## Polling Strategy

Recommended approach for waiting on job completion:

1. Submit job, receive `jobId`
2. Poll `GET /api/jobs/{jobId}` every 5-10 seconds
3. Check `job.status` — when `completed` or `failed`, stop polling
4. Download completed images individually via `GET /api/jobs/{jobId}/images/{imageId}`

For large jobs, you can start downloading completed images while the job is still `processing` — check each image's `status` field.

## Example: Full Image Generation Flow

```bash
# 1. Login
curl -c cookies.txt -X POST https://diemshare.example.com/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"agent","password":"secret"}'

# 2. Submit job
curl -b cookies.txt -X POST https://diemshare.example.com/api/jobs \
  -H 'Content-Type: application/json' \
  -d '{
    "job_type": "image",
    "defaults": {"model": "seedream-v4", "width": 1024, "height": 1024},
    "images": [{"prompt": "a futuristic city at night"}]
  }'
# Response: {"jobId":"abc123","estimatedCost":0.025}

# 3. Poll status
curl -b cookies.txt https://diemshare.example.com/api/jobs/abc123

# 4. Download result (once image status is "completed")
curl -b cookies.txt -o output.png \
  https://diemshare.example.com/api/jobs/abc123/images/img_001
```
