[ Skills ]

Lab Nocturne Images works natively with CLI agents through skills. Install once, and your agent can upload, list, and manage images with natural language.

Install

Add image skills to your agent with a single command:

Install skills
npx skills install jjenkins/agent-image-skills

Available Skills

Once installed, your agent has access to the following skills:

SkillTriggerDescription
image-upload"upload this image"Upload an image and get back a CDN URL
image-files"list my images"List uploaded files with pagination and sorting
image-stats"show my usage"View storage, bandwidth, and quota usage
image-delete"delete this image"Soft-delete a file by ID
image-key"get an API key"Generate a test API key instantly

Compatibility: Works with Claude Code, OpenClaw, and any CLI agent that supports skills.

[ API Documentation ]

Everything below works with skills or raw HTTP. Install the skills above for the fastest path, or use curl if you prefer working directly with the API.

Try it now: Generate an API key and all code examples will update with your real key.

Quick Start

Get from zero to first upload in under 60 seconds:

1. Get your API key
curl https://images.labnocturne.com/key
Response
{
  "api_key": "ln_test_...",
  "type": "test",
  "message": "Test key created! Files are deleted after 7 days."
}
2. Upload an image
curl -X POST https://images.labnocturne.com/upload \
  -H "Authorization: Bearer {{API_KEY}}" \
  -F "[email protected]"
Response
{
  "id": "img_01arz3ndektsv4rrffq69g5fav",
  "url": "https://images.labnocturne.com/i/01ARZ3NDEKTSV4RRFFQ69G5FAV.jpg",
  "size": 245680,
  "uploaded_at": "2024-12-02T10:30:00Z"
}
3. Use your image
<img src="https://images.labnocturne.com/i/01ARZ3NDEKTSV4RRFFQ69G5FAV.jpg" />
Image served from CDN • Cached globally • Fast forever

Authentication

All authenticated endpoints require a Bearer token in the Authorization header. Test keys start with ln_test_, live keys with ln_live_.

Authorization Header Format
Authorization: Bearer {{API_KEY}}

GET /key

Generate a test API key instantly. No email or payment required. Test keys have 100MB storage, 1GB bandwidth, and files auto-delete after 7 days.

Request

Authentication: None required

Example Request
curl https://images.labnocturne.com/key

Response

200 OK
{
  "api_key": "{{API_KEY}}",
  "type": "test",
  "message": "Test key created! Files are deleted after 7 days.",
  "limits": {
    "max_file_size_mb": 10,
    "storage_mb": 100,
    "bandwidth_gb_per_month": 1,
    "rate_limit_per_hour": 100
  },
  "docs": "https://images.labnocturne.com/docs"
}

Errors

500 Internal Server Error
{
  "error": {
    "message": "Failed to generate API key. Please try again.",
    "type": "internal_error",
    "code": "key_generation_failed"
  }
}

POST /upload

Upload an image file and get back a CDN URL. Supports JPG, PNG, GIF, WebP, and SVG formats.

Request

Authentication: Required (Bearer token)

Content-Type: multipart/form-data

Parameters

ParameterTypeRequiredDescription
filefileYesImage file (jpg, png, gif, webp, svg). Max 10MB for test keys, 100MB for paid.
Example Request
curl -X POST https://images.labnocturne.com/upload \
  -H "Authorization: Bearer {{API_KEY}}" \
  -F "[email protected]"

Response

201 Created
{
  "id": "img_01arz3ndektsv4rrffq69g5fav",
  "url": "https://images.labnocturne.com/i/01ARZ3NDEKTSV4RRFFQ69G5FAV.jpg",
  "size": 245680,
  "uploaded_at": "2024-12-02T10:30:00Z"
}

Errors

401 Unauthorized
{
  "error": {
    "message": "Invalid API key",
    "type": "unauthorized",
    "code": "invalid_api_key"
  }
}
400 Bad Request
{
  "error": {
    "message": "File type not supported. Allowed: jpg, png, gif, webp, svg",
    "type": "invalid_file_type",
    "code": "unsupported_file_type"
  }
}
413 Request Entity Too Large
{
  "error": {
    "message": "File size exceeds limit for test keys (10MB). Upgrade to increase limits.",
    "type": "file_too_large",
    "code": "file_size_exceeded",
    "docs": "https://images.labnocturne.com/docs#rate-limits"
  }
}
429 Too Many Requests
{
  "error": {
    "message": "Rate limit exceeded. Limit: 100 requests/hour. Resets at 2025-12-04T02:46:24Z.",
    "type": "rate_limit_exceeded",
    "code": "rate_limit_exceeded",
    "limit": 100,
    "reset_at": "2025-12-04T02:46:24Z"
  }
}

GET /i/:ulid.:ext

Retrieve a file via our global CDN. This is a public endpoint (no authentication required). Files are served with optimal caching and global distribution for fast delivery.

Request

Authentication: None required

URL Pattern: /i/{ULID}.{ext}

Example Request
curl https://images.labnocturne.com/i/01ARZ3NDEKTSV4RRFFQ69G5FAV.jpg

Response

Returns a 302 Found redirect to the CDN URL. Images are cached globally for optimal performance and fast delivery worldwide.

Response Headers

Cache-Control: public, max-age=31536000, immutable Content-Type: image/jpeg

Errors

404 Not Found

Returns a 1x1 transparent PNG for better UX in <img> tags.

DELETE /i/:id

Delete a file. You can only delete files you own.

Request

Authentication: Required (Bearer token)

Path Parameter: id - File ID in img_* format

Example Request
curl -X DELETE https://images.labnocturne.com/i/img_01arz3ndektsv4rrffq69g5fav \
  -H "Authorization: Bearer {{API_KEY}}"

Response

200 OK
{
  "success": true,
  "message": "File deleted successfully"
}

Errors

401 Unauthorized
{
  "error": {
    "message": "Invalid API key",
    "type": "unauthorized",
    "code": "invalid_api_key"
  }
}
404 Not Found
{
  "error": {
    "message": "File not found",
    "type": "not_found",
    "code": "file_not_found"
  }
}

GET /files

List all files for your account with pagination and sorting options.

Request

Authentication: Required (Bearer token)

Query Parameters

ParameterTypeDefaultDescription
limitinteger100Number of files to return (max 100)
offsetinteger0Number of files to skip
sortstringuploaded_at_descSort order: uploaded_at_desc, uploaded_at_asc, size_desc, size_asc
Example Request
curl "https://images.labnocturne.com/files?limit=10&offset=0&sort=uploaded_at_desc" \
  -H "Authorization: Bearer {{API_KEY}}"

Response

200 OK
{
  "files": [
    {
      "id": "img_01arz3ndektsv4rrffq69g5fav",
      "url": "https://images.labnocturne.com/i/01ARZ3NDEKTSV4RRFFQ69G5FAV.jpg",
      "filename": "photo.jpg",
      "size": 245680,
      "mime_type": "image/jpeg",
      "uploaded_at": "2024-12-02T10:30:00Z"
    }
  ],
  "pagination": {
    "total": 42,
    "limit": 10,
    "offset": 0,
    "next": "https://images.labnocturne.com/files?limit=10&offset=10"
  }
}

Errors

400 Bad Request
{
  "error": {
    "message": "Invalid sort order. Must be one of: uploaded_at_desc, uploaded_at_asc, size_desc, size_asc",
    "type": "invalid_request",
    "code": "invalid_sort_order"
  }
}

GET /stats

Get comprehensive usage statistics including storage, bandwidth, API requests, and quotas.

Request

Authentication: Required (Bearer token)

Example Request
curl https://images.labnocturne.com/stats \
  -H "Authorization: Bearer {{API_KEY}}"

Response

200 OK
{
  "storage": {
    "used_bytes": 12582912,
    "used_mb": 12.0,
    "quota_bytes": 104857600,
    "quota_mb": 100.0,
    "percentage_used": 12.0
  },
  "files": {
    "count": 42,
    "quota": null
  },
  "bandwidth": {
    "used_bytes": 0,
    "used_mb": 0.0,
    "quota_bytes": 1073741824,
    "quota_mb": 1024.0,
    "percentage_used": 0.0
  },
  "api_requests": {
    "count": 5,
    "quota": 100,
    "period": "hour",
    "resets_at": "2025-12-04T03:00:00Z"
  },
  "account": {
    "key_type": "test",
    "created_at": "2024-12-01T15:30:00Z"
  }
}

Error Handling

All API errors follow a consistent JSON format:

Error Response Format
{
  "error": {
    "message": "Human-readable error message",
    "type": "error_category",
    "code": "machine_readable_error_code"
  }
}

Common Error Codes

HTTP StatusError CodeDescription
401invalid_api_keyAPI key is missing or invalid
400missing_fileFile parameter missing in upload request
400unsupported_file_typeFile type not supported
404file_not_foundRequested file doesn't exist or was deleted
413file_size_exceededFile exceeds size limit for your plan
429rate_limit_exceededToo many requests, wait for rate limit reset

Rate Limit Headers

All authenticated endpoints return rate limit information in response headers:

X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1638460800

When rate limited, a 429 Too Many Requests response includes a Retry-After header indicating seconds until reset.

Rate Limits & Quotas

Quotas vary by plan tier. Upgrade to increase your limits.

FeatureTestStarterPro
Storage100 MB10 GB100 GB
Bandwidth1 GB/month50 GB/month500 GB/month
Rate Limit100 requests/hour1,000 requests/hour10,000 requests/hour
Max File Size10 MB100 MB100 MB
Retention7 daysUnlimitedUnlimited
PriceFree$9/month$29/month

IP-Based Rate Limits

To prevent abuse, test key generation is rate limited per IP address:

  • Test Key Generation: 5 keys per hour per IP address
  • Response Code: 429 Too Many Requests when exceeded
  • Reset: Limits reset hourly

Note: IP-based limits apply only to GET /key. Authenticated API requests are limited by your plan's quota (shown above).

Need more? Check out our pricing page for plan details and upgrade options.