# Quickstart

Get from zero to a working public file URL in under 5 minutes.

CurlyFlies is temporary file storage for AI agents. You upload a file, you get back a clean public URL that works in an incognito window with no auth, no redirects, and correct `Content-Type` headers. Files expire automatically (24 hours by default).

## 1. Get an API key

Two ways:

**Human way** — sign in at [curlyflies.com/dashboard](https://curlyflies.com/dashboard) with an email magic link. Your key is on the **API Keys** tab.

**Agent way** — self-provision a key with one API call, no human required:

```bash
curl -X POST https://curlyflies.com/v1/agent/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "agent@workflow.ai", "agent_name": "my-n8n-workflow"}'
```

Response:

```json
{
  "api_key": "curly_live_abc123",
  "plan": "free",
  "uploads_remaining": 100,
  "message": "API key created. Store it securely — it won't be shown again."
}
```

Store the key. It is shown exactly once. Keys look like `curly_live_{32 chars}` (or `curly_test_` for test keys).

## 2. Upload your first file

```bash
export CURLY_KEY="curly_live_abc123"

curl -X POST https://curlyflies.com/v1/upload \
  -H "Authorization: Bearer $CURLY_KEY" \
  -F "file=@output.png"
```

Response (under 200ms):

```json
{
  "file_id": "x7k2p9",
  "url": "https://curlyflies.com/f/x7k2p9.png",
  "expires_at": "2026-06-02T09:41:00Z",
  "size_bytes": 204800,
  "content_type": "image/png",
  "delete_token": "dt_abc123"
}
```

## 3. Verify it works

Paste the `url` into an incognito browser window. The raw file loads — no login wall, no redirect, no cookies. That's why Instagram's Graph API, Buffer, and Meta Ads accept these URLs without error 9004.

## 4. Use the URL

Pass it anywhere a public URL is expected:

- Instagram Graph API `POST /{ig-user-id}/media` with `image_url`
- Buffer / Meta Ads creative uploads
- Webhooks and downstream agents
- Any API that fetches files by URL

The file vanishes at `expires_at`. Always read `expires_at` from the response — every response that contains a URL includes it.

## Common variations

**Re-host a remote URL** (GPT Image, Nano Banana, Seedream, Replicate, Higgsfield signed URLs, etc.):

```bash
curl -X POST https://curlyflies.com/v1/upload-url \
  -H "Authorization: Bearer $CURLY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://oaidalleapiprodscus.blob.core.windows.net/private/gen/abc123.png?se=..."}'
```

**Upload base64 instead of a file:**

```bash
curl -X POST https://curlyflies.com/v1/upload \
  -H "Authorization: Bearer $CURLY_KEY" \
  -F "content_base64=$(base64 -i output.png)" \
  -F "filename=output.png"
```

**Custom TTL** (paid plans):

```bash
curl -X POST https://curlyflies.com/v1/upload \
  -H "Authorization: Bearer $CURLY_KEY" \
  -F "file=@output.png" \
  -F "ttl_seconds=3600"
```

## Limits on the free plan

| | |
|---|---|
| Uploads | 100/month |
| Max file size | 5MB |
| TTL | 24h fixed |
| Rate limit | 100 requests/hour |

Allowed types: `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `video/mp4`, `video/quicktime`, `application/pdf`, `text/plain`, `application/json`. Executables and standalone HTML/JS are rejected.

## Next steps

- [REST API reference](/docs/api.md) — every endpoint, every field
- [MCP server setup](/docs/mcp.md) — let your agent call `upload_file` as a native tool
- [SDK patterns](/docs/sdks.md) — Python and JavaScript snippets
