# Sparkle External API — cheat sheet for LLMs and agents > For OpenClaw, Cursor, Claude Code, Codex, and similar agents that write integration code. > Spec: https://sparkle.956.jp/openapi.yaml > Human help: https://sparkle.956.jp/help_admin.html#external-api > Do not scrape /login, /company/, /portal/, /admin/, or JWT session APIs. Last updated: 2026-09-03 Host: `https://sparkle.956.jp` --- ## What this API is Server-to-server RAG against **one company's published PDFs**. It is **not** the browser session API used by `/company` and `/portal`. ## Auth (pick one) ``` Authorization: Bearer X-Sparkle-Security-Key: ``` Keys are issued by a Sparkle **super admin** on the company detail page (plain text shown once). Store as `SPARKLE_SECURITY_KEY`. Never commit the key. Never put it in client-side JS. ## Endpoints (only these) | Method | Path | Purpose | |--------|------|---------| | POST | `/api/v1/external/rag/query` | Ask a question | | GET | `/api/v1/external/documents/{id}/preview` | Inline PDF for a cited `document_id` | Base URL production: `https://sparkle.956.jp` ## POST /api/v1/external/rag/query Headers: `Content-Type: application/json` + auth. ```json { "question": "就業規則の有給は何日?", "include_sources": true, "history": [ { "role": "user", "content": "前回の質問" }, { "role": "assistant", "content": "前回の回答" } ] } ``` Nested form also works: `{ "rag": { "question": "...", "include_sources": true } }`. **200** ```json { "answer": "...", "sources": [ { "document_id": 1, "title": "就業規則", "excerpt": "...", "document_vectorized_at": "2026-09-01T00:00:00Z" } ], "company_id": 1, "company_slug": "example" } ``` Empty corpus / no hits still **200** with `answer` like `情報を見つけることができませんでした。` and `sources: []`. ## curl ```bash curl -sS -X POST "https://sparkle.956.jp/api/v1/external/rag/query" \ -H "Authorization: Bearer $SPARKLE_SECURITY_KEY" \ -H "Content-Type: application/json" \ -d '{"question":"有給休暇の日数は?","include_sources":true}' ``` ## Errors (`code` field) | HTTP | code | Meaning | |------|------|---------| | 401 | unauthorized | Bad or missing key | | 403 | company_inactive | Company suspended | | 422 | question_blank | Empty question | | 422 | invalid_request | Bad payload | | 422 | question_limit | Monthly question quota | | 429 | rate_limited | Per-minute rate limit | | 502 | llm_unavailable | LLM not configured / generation failed | | 404 | not_found | Preview: unpublished or missing file | ## Hard rules for generated code 1. Call **only** `/api/v1/external/*`. Do not use `/api/v1/company/*`, `/api/v1/portal/*`, `/api/v1/auth/*`. 2. Scope is **all published documents** (no access-group filter). Do not claim per-user ACL on this API. 3. Successful queries increment the **monthly question quota**. Batch/crawl loops will burn the plan. 4. Do not create portal threads; this API does not. 5. Cite `sources[].title` / `document_id` when showing answers to humans. 6. PDF only. No Word/Excel upload via this API (there is no upload endpoint here). 7. Prefer OpenAPI codegen from https://sparkle.956.jp/openapi.yaml over inventing paths. ## OpenClaw / agent wiring - Env: `SPARKLE_BASE_URL` (default `https://sparkle.956.jp`), `SPARKLE_SECURITY_KEY` - Tool: HTTP POST JSON as above; timeout ≥ 60s (LLM generation) - After answer: if user wants the PDF, GET preview with the same key - If 429 or question_limit: stop retry storms; tell the human to wait or buy question packs on `/company/billing` ## Related - Product: https://sparkle.956.jp/sparkle.html - Briefs: https://sparkle.956.jp/llms.txt , https://sparkle.956.jp/llms-full.txt