# Sideload Agent API

Generate 3D avatars programmatically using the x402 payment protocol.

**Base URL:** `https://sideload.gg`
**Cost:** 2 USDC per generation
**Payment:** x402 protocol (USDC on Base, chain ID 8453)
**Rate Limit:** 10 generations per 30 minutes per wallet

---

## Quick Start

### Generate from text

```
POST https://sideload.gg/api/agent/generate
Content-Type: application/json
x-payment: <x402_payment_token>

{
  "type": "text",
  "prompt": "A cyberpunk samurai with glowing red armor"
}
```

### Generate from image

```
POST https://sideload.gg/api/agent/generate
Content-Type: application/json
x-payment: <x402_payment_token>

{
  "type": "image",
  "imageUrl": "https://example.com/character.png"
}
```

Poll the returned `statusUrl` until the job completes, then use the result URLs.

---

## Payment

This API uses the [x402 protocol](https://www.x402.org/) for payment. x402 is an open standard for HTTP-native payments — your client handles payment automatically on every request.

**Payment details:**
- **Token:** USDC
- **Chain:** Base (chain ID 8453)
- **Amount:** 2 USDC per generation
- **USDC contract:** `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`

If you send a request without a valid payment header, the API returns `402 Payment Required` with the payment instructions your x402 client needs to complete the transaction.

### Compatible clients

Any x402-compatible HTTP client will work. Examples:
- [Thirdweb x402](https://portal.thirdweb.com/payments/x402) — built-in facilitator
- [x402 TypeScript SDK](https://github.com/coinbase/x402)

---

## Endpoints

### Generate Avatar

```
POST /api/agent/generate
```

**Headers:**
| Header | Required | Description |
|--------|----------|-------------|
| `Content-Type` | Yes | `application/json` |
| `x-payment` | Yes | x402 payment token |

**Body (JSON):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | `"text"` or `"image"` | Yes | Generation mode |
| `prompt` | string | If type is `"text"` | Text description of the avatar |
| `imageUrl` | string | If type is `"image"` | Public URL of a reference image |

---

### Text Generation

Use `type: "text"` to generate an avatar from a text description.

```json
{
  "type": "text",
  "prompt": "A medieval knight with silver armor and a glowing energy shield"
}
```

**Tips for prompts:**
- Be specific about appearance: clothing, colors, accessories
- Describe the character's style: realistic, anime, cartoon, cyberpunk
- Include distinctive features: armor, weapons, hairstyle, wings

**Example prompts:**
- `"A steampunk engineer with a leather tool belt, copper mechanical arm, and weathered pilot hat"`
- `"An anime-style sorceress with long silver hair, glowing purple eyes, and ornate golden staff"`
- `"A futuristic soldier in white and blue power armor with a glowing energy shield"`

---

### Image Generation

Use `type: "image"` to generate an avatar from a reference image. The API will fetch the image from the URL you provide and use it as the basis for the 3D avatar.

```json
{
  "type": "image",
  "imageUrl": "https://example.com/my-character.png"
}
```

**Image requirements:**
- **Format:** PNG, JPG, or WebP
- **URL:** Must be publicly accessible (no authentication)
- **Content:** Works best with character artwork, portraits, or full-body images
- **Quality:** Higher resolution images produce better results

**What works well:**
- Character art with clear outlines
- Front-facing portraits or full-body shots
- Images with distinct clothing and features
- AI-generated character images

**What doesn't work well:**
- Images with multiple characters
- Very dark or low-contrast images
- Heavily cropped or partial images

---

### Response

**Success (200):**
```json
{
  "success": true,
  "jobId": "avt-a1b2c3d4",
  "status": "processing",
  "statusUrl": "/api/agent/generate/avt-a1b2c3d4/status",
  "message": "Avatar generation started. Poll the statusUrl to check progress."
}
```

**Error responses:**

| Status | Meaning |
|--------|---------|
| 400 | Invalid input (missing prompt, bad type, unreachable image URL) |
| 402 | Payment required — no valid x402 payment header |
| 429 | Rate limit exceeded — check `Retry-After` header |
| 503 | Service paused or temporarily unavailable |

---

### Poll Status

```
GET /api/agent/generate/{jobId}/status
```

No payment or authentication required. Poll this endpoint to track progress.

**Response — processing:**
```json
{
  "jobId": "avt-a1b2c3d4",
  "status": "processing",
  "step": "generating_model",
  "stepDescription": "Generating 3D model",
  "progress": 50
}
```

**Response — completed:**
```json
{
  "jobId": "avt-a1b2c3d4",
  "status": "completed",
  "result": {
    "glbUrl": "https://aiml.sideload.gg/models/avt-a1b2c3d4.glb",
    "vrmUrl": "https://aiml.sideload.gg/models/avt-a1b2c3d4.vrm",
    "mml": "<m-character src=\"https://aiml.sideload.gg/models/avt-a1b2c3d4.glb\"></m-character>",
    "mmlUrl": "https://aiml.sideload.gg/mml/avt-a1b2c3d4",
    "processedImageUrl": "https://aiml.sideload.gg/images/avt-a1b2c3d4_processed.png"
  }
}
```

**Response — failed:**
```json
{
  "jobId": "avt-a1b2c3d4",
  "status": "failed",
  "error": "Generation failed"
}
```

---

## Result Fields

| Field | Format | Description |
|-------|--------|-------------|
| `glbUrl` | URL (.glb) | 3D model in GLB format — use this for rendering engines |
| `vrmUrl` | URL (.vrm) | Avatar in VRM format — compatible with VRM viewers and apps |
| `mml` | MML markup | MML tag for metaverse environments (e.g. `<m-character src="...">`) |
| `mmlUrl` | URL | MML document URL — for metaverse environments supporting MML |
| `processedImageUrl` | URL (.png) | The processed reference image used for generation |

---

## Integration Examples

### Poll until complete

```typescript
async function waitForCompletion(jobId: string): Promise<any> {
  const maxAttempts = 60;
  const interval = 5000; // 5 seconds

  for (let i = 0; i < maxAttempts; i++) {
    const response = await fetch(
      `https://sideload.gg/api/agent/generate/${jobId}/status`
    );
    const data = await response.json();

    if (data.status === "completed") return data.result;
    if (data.status === "failed") throw new Error(data.error);

    await new Promise(r => setTimeout(r, interval));
  }

  throw new Error("Generation timed out");
}
```

### Full flow — text prompt

```typescript
// 1. Start generation (x402 client handles payment automatically)
const response = await x402Client.post(
  "https://sideload.gg/api/agent/generate",
  {
    type: "text",
    prompt: "A futuristic robot with chrome plating",
  }
);

// 2. Poll for result
const result = await waitForCompletion(response.jobId);

// 3. Use the avatar
console.log("GLB model:", result.glbUrl);
console.log("VRM avatar:", result.vrmUrl);
console.log("MML markup:", result.mml);
```

### Full flow — image reference

```typescript
// 1. Start generation from an image
const response = await x402Client.post(
  "https://sideload.gg/api/agent/generate",
  {
    type: "image",
    imageUrl: "https://my-storage.com/character-art.png",
  }
);

// 2. Poll for result
const result = await waitForCompletion(response.jobId);

// 3. Compare the processed image with original
console.log("Processed image:", result.processedImageUrl);
console.log("Final avatar:", result.vrmUrl);
```

---

## Rate Limits

- **10 generations per 30 minutes** per wallet address
- Rate limit info is returned in response headers:
  - `X-RateLimit-Remaining` — requests left in current window
  - `Retry-After` — seconds until rate limit resets (on 429 responses)

---

## Notes

- Generations typically take 2-5 minutes to complete
- Poll the status endpoint every 5 seconds — it's free and has no rate limit
- The `processedImageUrl` shows what the AI "saw" when generating your avatar
- The service may be temporarily paused for maintenance (503 response)

---

## Support

For questions or issues, contact the Sideload team or open an issue on the project repository.
