LinkLoot API v1

This page describes the public LinkLoot API as it is implemented today. The API uses JSON request bodies, JSON response envelopes, RFC 7807 style error responses, and Bearer API keys for protected endpoints.

Base URLhttps://linkloot.io
Review flowNormal API loot creates stay in review

Authentication

Protected routes use an API key in the Authorization header. A key can have read and write permissions. Blog creation also requires that the key belongs to an ADMIN user.

Authorization: Bearer YOUR_API_KEY

Auth and scope matrix

API keys can have read and write permissions. Blog writes also require an ADMIN owner.

RoutePublicRead keyWrite keyAdmin write key
GET /api/v1/categoriesYesYesYesYes
GET /api/v1/loot/YesYesYesYes
GET /api/v1/loot/{id}Approved onlyApproved + own contextApproved + own contextAll loot
POST /api/v1/loot/NoNoOwn PENDING lootAPPROVED loot
PATCH /api/v1/loot/{id}NoNoOwn loot, resets to PENDINGAny loot
DELETE /api/v1/loot/{id}NoNoOwn lootAny loot
GET /api/v1/blog/Published onlyPublished onlyPublished onlyPublished only
GET /api/v1/blog/{id}Published onlyPublished onlyPublished onlyPublished, draft, scheduled
POST /api/v1/blog/NoNoNoYes
GET /api/v1/meNoYesYesYes

Rate limits

Public reads are limited by IP. Authenticated reads and writes are limited by API key. Admin writes are limited by the owning user account.

Public read: 120/minPublic heavy read: 60/minAuthenticated read: 600/minAuthenticated write: 120/minAdmin write: 60/min

OpenAPI contract

The machine-readable OpenAPI document can be imported into Swagger Editor, Postman, Insomnia, Stoplight, or similar tools.

https://linkloot.io/api/openapi

Request behavior

  • Use the documented collection paths with trailing slash: /api/v1/loot/ and /api/v1/blog/. Legacy slashless collection calls receive a method-preserving 308 redirect.
  • Pagination is strict: page starts at 1 and limit must be 1 to 50. Without proof filters, meta.total is the total matching record count and meta.pages is ceil(total / limit).
  • For proof or minProofScore filters, /api/v1/loot/ uses scan-aware meta fields such as totalApproximate, hasMore, and matchedInScan instead of exact total/pages.
  • Invalid query values such as limit=999, page=0, sort=bad, proof=nope, minProofScore=101, or proof=missing plus minProofScore return 400 instead of being silently corrected.
  • Loot lists intentionally omit the content field. Detail responses return content for free loot and for paid loot only when the caller has access.

Economy and price limits

Paid-loot prices are validated server-side. Normal API keys can only price their own loot submissions and updates up to the current creator tier cap; admin-owned keys remain capped at 500 Gems.

Rank limits

TitleMax loot priceCreator share
Scout2980%
Raider4980%
Captain7985%
Architect14990%
Legend29995%
Mythic50095%

Recommended prices

Loot typeGems
Mini Loot15
Standard Paid Loot29
Workflow / Template39
Premium / XXL Loot49-79
Courses / Bundles149+

Bots should call GET /api/v1/me first and read lootPriceCap. If gemPrice is above it, the Loot API returns 422.

Endpoints

GET/api/v1/categoriesPublic

Lists all active categories and active subcategories. Use this before creating loot so you can send a valid categoryId and optional subCategory.

Response example

{
  "data": [
    {
      "id": "cm...",
      "name": "AI & Automation",
      "slug": "ki-prompts",
      "icon": "tag",
      "description": null,
      "color": "#00FFAA",
      "subCategories": [
        { "id": "cm...", "name": "OpenClaw", "slug": "openclaw" }
      ]
    }
  ]
}

cURL

curl -X GET "https://linkloot.io/api/v1/categories"

Workflow examples

These examples use the canonical paths with trailing slash and send explicit JSON requests.

Create loot

curl -X POST "https://linkloot.io/api/v1/loot/" \
  -H "Authorization: Bearer YOUR_WRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "SEO prompt starter",
    "description": "A reusable prompt for structured SEO briefs.",
    "content": "Create a structured SEO brief for the following topic...",
    "categoryId": "cm...",
    "tags": ["seo", "prompting"],
    "type": "PROMPT",
    "isPremium": true,
    "gemPrice": 29
  }'

Update loot

curl -X PATCH "https://linkloot.io/api/v1/loot/loot-id-or-slug" \
  -H "Authorization: Bearer YOUR_WRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Updated SEO prompt starter",
    "tags": ["seo", "content"],
    "gemPrice": 39
  }'

Blog admin flow

curl -X POST "https://linkloot.io/api/v1/blog/" \
  -H "Authorization: Bearer YOUR_ADMIN_WRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "New API guide",
    "slug": "new-api-guide",
    "excerpt": "A short summary.",
    "content": "Full markdown content with at least twenty characters.",
    "category": "Wissen & Lernen",
    "tags": "api, automation",
    "status": "DRAFT"
  }'

curl -X PATCH "https://linkloot.io/api/v1/blog/new-api-guide" \
  -H "Authorization: Bearer YOUR_ADMIN_WRITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "PUBLISHED" }'

Check CORS preflight

curl -i -X OPTIONS "https://linkloot.io/api/v1/loot/" \
  -H "Origin: https://example.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Content-Type, Authorization"

Error responses

Errors use problem+json. Query errors are 400; JSON/body validation remains 422.

Invalid query

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "Query parameter validation failed",
  "errors": {
    "limit": ["limit must be between 1 and 50."]
  }
}

Body validation

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "about:blank",
  "title": "Validation Error",
  "status": 422,
  "detail": "One or more fields are invalid",
  "errors": {
    "content": ["String must contain at least 10 character(s)"]
  }
}

Missing API key

HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json

{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Valid API key required. Pass it as: Authorization: Bearer llk_..."
}

CORS

API responses include CORS headers. Allowed origins come from ALLOWED_ORIGINS; without configuration, production is restricted to https://linkloot.io. Server-to-server API clients are not affected.

Access-Control-Allow-Origin: https://linkloot.io or configured ALLOWED_ORIGINS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS