Skip to content

API Reference — Internal

Base URL (prod): https://littlebig-license-server.andredaus.workers.dev

Validate a license key and register/refresh a domain activation.

Request body:

{ "key": "LBL-XXXX-XXXX-XXXX-XXXX", "domain": "example.com" }

Response 200:

{
"valid": true,
"licenseId": "...",
"status": "active",
"tier": "silver",
"features": { "llm_proxy": true, "credits_included": 50 },
"credits": { "balance": 42, "unlimited": false },
"seatLimit": 3,
"activations": 1,
"expiresAt": null
}

Remove a domain activation.

Request body: { "key": "...", "domain": "example.com" }

Behavioral verdict-quality signal from WP Luminary installs (no UI buttons — signals derive from observed admin actions). Auth: valid active license key in the body.

Request body:

{
"key": "LBL-XXXX-XXXX-XXXX-XXXX",
"verdict": "disputed",
"path_hash": "<sha256 hex of site-relative path>",
"scan_status": "flagged",
"risk_level": 9,
"wpl_version": "1.4.8"
}
  • verdict: disputed (admin ignored a flagged file) or remediated (flagged file deleted/changed by next crawl)
  • scan_status: suspicious | flagged | auto_flagged (defaults to flagged)
  • Rate limit: 500 events per license per day → 429 rate_limited
  • Errors: 400 missing_fields | invalid_verdict | invalid_path_hash, 403 invalid_license

Stored in the scan_feedback D1 table (migration 0003_scan_feedback.sql). No PII: hashes only, no domains, no file content.

Plugin Update Checker (PUC)–compatible update JSON. Returns a signed R2 URL (1h TTL) for the latest ZIP.


All /v1/admin/* routes require Authorization: Bearer {ADMIN_TOKEN} header.

Method Path Description
POST /v1/admin/products Create product
POST /v1/admin/tiers Create tier
POST /v1/admin/licenses Issue license (generates LBL-XXXX-XXXX-XXXX-XXXX key, seeds credits)
PATCH /v1/admin/licenses/:id Update status / expires / seat_limit / features_override / notes
GET /v1/admin/licenses List licenses (filters: product_id, status, customer_email, limit, offset)
POST /v1/admin/credits/grant Add or deduct credits (delta + reason)
POST /v1/admin/versions Register plugin ZIP in R2

Base URL (prod): https://littlebig-wp-luminary-proxy.andredaus.workers.dev

Structured scan. Worker owns prompt; plugin sends payload only.

Request body:

{
"key": "LBL-XXXX-XXXX-XXXX-XXXX",
"scan_type": "file",
"payload": {
"path": "wp-content/plugins/my-plugin/bad.php",
"content": "<base64-encoded file content>",
"size": 4096
},
"meta": {
"wp_version": "6.7",
"wpl_version": "1.2.0",
"plugin_version": "2.3.1"
}
}

Response 200:

{
"risk_level": 3,
"status": "suspicious",
"summary": "File contains base64-encoded eval calls consistent with PHP webshell patterns.",
"findings": ["eval(base64_decode(...))", "gzinflate usage"],
"patterns": ["eval_base64", "eval_gzinflate"],
"tokens": { "input": 1240, "output": 312 }
}

Response 402 (credits exhausted):

{ "error": "credits_exhausted" }

Returns dynamic scan configuration. Cached 24h by the plugin.

Request body: { "key": "LBL-XXXX-XXXX-XXXX-XXXX" }

Response: See scan-config.ts SCAN_CONFIG constant for current values.

Direct streaming proxy to Anthropic. Plugin provides its own apiKey in the request. Response is SSE stream from Anthropic.

Anonymized threat intelligence feed for WAF integrations.

Response:

{
"generated_at": "2026-06-30T12:00:00Z",
"pattern_stats": [
{ "pattern_name": "eval_base64", "scan_type": "file", "occurrences": 142, "last_seen": "2026-06-30" }
],
"recent_threats": [
{ "scan_type": "file", "file_ext": ".php", "risk_level": 4, "patterns": ["eval_base64"], "reported_date": "2026-06-30" }
],
"flagged_plugins": [
{ "plugin_slug": "abandoned-plugin", "occurrences": 12, "last_seen": "2026-06-29" }
]
}

license-server: catalog, community and operations (added October 2026)

Section titled “license-server: catalog, community and operations (added October 2026)”

Base URL: https://license.littlebig.co. Admin endpoints need Authorization: Bearer {ADMIN_TOKEN}; the Product Admin sends the editor’s identity in X-Admin-Identity for the audit log.

Method and path Purpose
GET /v1/catalog Active products sold through Paddle with their active prices in the current environment. Names, price wording and Paddle price IDs only; cached 60 s; used by the EmDash price picker and the landing pages
Method and path Purpose
GET /v1/admin/catalog Products with tiers, prices, steps, license counts
POST /v1/admin/catalog/products Create a product (409 if the slug is taken). With a community kind it also creates the course or space as a draft
PATCH /v1/admin/catalog/products/:id Edit; name and description are pushed to Paddle
POST /v1/admin/catalog/products/:id/archive Archive the product, its tiers and its Paddle prices. There is no delete
POST /v1/admin/catalog/products/:id/community Create or reuse the course or space (never publishes)
POST /v1/admin/catalog/tiers/:tierId/prices Create a Paddle price for a tier { amount_minor, currency, billing_cycle }
POST /v1/admin/catalog/prices/:priceId/replace New price at a new amount, old one archived { amount_minor }
POST /v1/admin/catalog/sync-paddle Read amounts from Paddle (read only)
POST /v1/admin/tiers, PATCH /v1/admin/tiers/:id Now also accept trial_days and attributes

POST /v1/admin/licenses checks the email address first (422 email_blocked / email_warning; send confirm_email: true to accept a warning). Creating or reactivating a license enrols the customer in the community; PATCH with status: "canceled" or "expired" removes access (unless another active license grants it).

Method and path Purpose
GET /v1/admin/community/check?slug= Read only: API user, courses and owners, member list shape
DELETE /v1/admin/community/courses/:slug Delete an empty draft course owned by the API user (refuses published courses, courses with students, sections or lessons, or courses owned by anyone else)
POST /v1/admin/reconcile Daily check; { "apply": true } changes things, anything else only reports
GET /v1/admin/reconcile/runs Recent runs with their reports
POST /v1/admin/mail/test Send one test email; says which provider delivered it
GET /v1/admin/email/check?email= What the address check says (creates and sends nothing)