{"openapi":"3.1.0","info":{"title":"Timeline of Everything API","version":"1.4.0","description":"Read and submit source-backed historical events. Public submissions are published immediately and enter an unmoderated operator queue."},"servers":[{"url":"https://timelineofeverything.online/api/timeline","description":"Public, anonymous, and Bearer API-key access"},{"url":"https://lowexpectations.dev/api/timeline","description":"Account-aware access; sends the existing lowexpectations.dev session cookie"}],"x-agent-guidance":{"firstRequest":"GET /limits","vocabularyRequest":"GET /options","requiredBeforeCreate":"POST /events/duplicate-check","exactDuplicateAction":"POST /contributions","rateLimitAction":"Stop writes until the reported window has elapsed; never retry in a loop.","tagCreation":"Include new clean tag names directly in EventSubmission.tags. Prefer at least three specific tags."},"paths":{"/":{"get":{"operationId":"discoverTimelineApi","summary":"Discover API endpoints and the agent workflow","responses":{"200":{"description":"Service discovery"}}}},"/limits":{"get":{"operationId":"getTimelineSubmissionLimits","summary":"Show authentication and submission-limit status","description":"Call this before writing. It reports current use, remaining writes, reset time, and batch size without consuming quota. Bearer keys work on either server entry; cookie authentication works only on lowexpectations.dev.","security":[{"timelineApiKey":[]},{"siteSession":[]},{}],"responses":{"200":{"description":"Current caller identity and exact application quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LimitsResponse"}}}},"401":{"description":"Bearer API key is invalid or revoked"}}}},"/events":{"get":{"operationId":"listTimelineEvents","summary":"List or search events","parameters":[{"name":"fromTick","in":"query","required":false,"description":"Signed chronology second","schema":{"type":"string"}},{"name":"toTick","in":"query","required":false,"description":"Signed chronology second","schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Full-text search","schema":{"type":"string"}},{"name":"types","in":"query","required":false,"description":"Comma-separated event types","schema":{"type":"string"}},{"name":"tags","in":"query","required":false,"description":"Comma-separated tag slugs","schema":{"type":"string"}},{"name":"locationId","in":"query","required":false,"description":"Location catalog ID","schema":{"type":"string"}},{"name":"referencesOnly","in":"query","required":false,"description":"Use 1 to require references","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"1–1000","schema":{"type":"string"}}],"responses":{"200":{"description":"Bounded event list"}}},"post":{"operationId":"createTimelineEvent","summary":"Publish an event and add it to the unmoderated queue","description":"Run the duplicate-check endpoint first. A 409 response includes canonical candidates. Fuzzy matches may be consciously overridden with duplicateOverride; exact title-and-date duplicates may only be overridden by an unlimited trusted account.","security":[{"timelineApiKey":[]},{"siteSession":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventSubmission"}}}},"responses":{"202":{"description":"Published"},"401":{"description":"Bearer API key is invalid or revoked"},"409":{"description":"Possible or exact duplicate; inspect code and matches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateResponse"}}}},"422":{"description":"Validation error"},"429":{"description":"Anonymous or standard-account submission limit reached"}}}},"/events/duplicate-check":{"post":{"operationId":"checkTimelineEventDuplicates","summary":"Score likely canonical duplicates without creating data","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventSubmission"}}}},"responses":{"200":{"description":"Ranked candidates and reasons","content":{"application/json":{"schema":{"type":"object","required":["matches"],"properties":{"matches":{"type":"array","items":{"$ref":"#/components/schemas/DuplicateMatch"}}}}}}},"422":{"description":"Validation error"}}}},"/events/batch":{"post":{"operationId":"createTimelineEventBatch","summary":"Validate, duplicate-check, and publish several events","description":"Returns one ordered result per input. Invalid and duplicate items do not consume quota. Successful events publish immediately and enter the unmoderated queue. Maximum batch size is returned by GET /limits.","security":[{"timelineApiKey":[]},{"siteSession":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["events"],"properties":{"events":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/EventSubmission"}}}}}}},"responses":{"202":{"description":"Every event was published"},"207":{"description":"Mixed per-event results; inspect the results array"},"401":{"description":"Bearer API key is invalid or revoked"},"422":{"description":"Invalid batch envelope or too many events"},"429":{"description":"Not enough remaining quota for eligible events"}}}},"/events/{id}":{"get":{"operationId":"getTimelineEvent","summary":"Fetch an event by ID or slug","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event"},"404":{"description":"Not found"}}}},"/contributions":{"post":{"operationId":"createTimelineContribution","summary":"Attach proposed tags, text, and references to an existing canonical event","security":[{"timelineApiKey":[]},{"siteSession":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetEventId","event"],"properties":{"targetEventId":{"type":"string"},"event":{"$ref":"#/components/schemas/EventSubmission"}}}}}},"responses":{"202":{"description":"Queued for moderation"},"401":{"description":"Bearer API key is invalid or revoked"},"429":{"description":"Submission limit reached"}}}},"/merge-requests":{"post":{"operationId":"createTimelineMergeRequest","summary":"Report two existing events as duplicates","security":[{"timelineApiKey":[]},{"siteSession":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sourceEventId","targetEventId"],"properties":{"sourceEventId":{"type":"string"},"targetEventId":{"type":"string"},"reason":{"type":"string","maxLength":1000}}}}}},"responses":{"202":{"description":"Queued for moderation"},"401":{"description":"Bearer API key is invalid or revoked"},"429":{"description":"Submission limit reached"}}}},"/options":{"get":{"operationId":"getTimelineOptions","summary":"List accepted submission types, searchable tags, tag policy, and location IDs","responses":{"200":{"description":"Submission and filter options. The types field is the vocabulary currently present in events; acceptedSubmissionTypes is authoritative for writes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptionsResponse"}}}}}}}},"components":{"securitySchemes":{"timelineApiKey":{"type":"http","scheme":"bearer","bearerFormat":"toe_live_…","description":"Recommended for AI agents. Generate a revocable timeline-only key at https://lowexpectations.dev/account/#api-access and send it as Authorization: Bearer <key>."},"siteSession":{"type":"apiKey","in":"cookie","name":"les_session","description":"Optional Low Expectations browser session. Valid only through the lowexpectations.dev server URL; do not copy this cookie into an AI agent."}},"schemas":{"LimitsResponse":{"type":"object","required":["authenticated","authenticationMethod","administrator","submissions","batchMaximum"],"properties":{"authenticated":{"type":"boolean","description":"True only when the server verified the request's credentials."},"authenticationMethod":{"enum":["anonymous","site_session","api_key"]},"account":{"oneOf":[{"type":"null"},{"type":"object","required":["username","displayName"],"properties":{"username":{"type":"string"},"displayName":{"type":"string"}}}]},"apiKey":{"oneOf":[{"type":"null"},{"type":"object","required":["label"],"properties":{"label":{"type":"string"}}}]},"administrator":{"type":"boolean"},"batchMaximum":{"type":"integer","minimum":1,"maximum":50},"submissions":{"type":"object","required":["unlimited","limit","used","remaining","resetSeconds","windowSeconds"],"properties":{"unlimited":{"type":"boolean"},"limit":{"oneOf":[{"type":"integer","minimum":1},{"type":"null"}]},"used":{"oneOf":[{"type":"integer","minimum":0},{"type":"null"}]},"remaining":{"oneOf":[{"type":"integer","minimum":0},{"type":"null"}]},"resetSeconds":{"oneOf":[{"type":"integer","minimum":0},{"type":"null"}]},"windowSeconds":{"oneOf":[{"type":"integer","minimum":1},{"type":"null"}]}}}},"examples":[{"authenticated":false,"authenticationMethod":"anonymous","account":null,"apiKey":null,"administrator":false,"batchMaximum":3,"submissions":{"unlimited":false,"limit":3,"used":0,"remaining":3,"resetSeconds":0,"windowSeconds":60}},{"authenticated":true,"authenticationMethod":"api_key","account":{"username":"example","displayName":"Example"},"apiKey":{"label":"My Codex"},"administrator":false,"batchMaximum":15,"submissions":{"unlimited":false,"limit":15,"used":2,"remaining":13,"resetSeconds":41,"windowSeconds":60}}]},"DuplicateResponse":{"type":"object","required":["ok","code","message","matches"],"properties":{"ok":{"const":false},"code":{"enum":["possible_duplicate","exact_duplicate"]},"message":{"type":"string"},"matches":{"type":"array","items":{"$ref":"#/components/schemas/DuplicateMatch"}}}},"DuplicateMatch":{"type":"object","required":["id","title","score","reasons"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"type":{"type":"string"},"score":{"type":"number","minimum":0,"maximum":1},"exact":{"type":"boolean","default":false},"reasons":{"type":"array","items":{"type":"string"}}}},"EventSubmission":{"type":"object","required":["title","description","type","startDate","tags"],"anyOf":[{"required":["sources"]},{"required":["reference"]}],"properties":{"title":{"type":"string","maxLength":160},"description":{"type":"string","maxLength":5000},"type":{"type":"string","enum":["birth","death","war","discovery","invention","political","politics","law","technology","economy","conflict","disaster","organization","science","religion","culture","society","personal","other"],"description":"Accepted write vocabulary; also returned as acceptedSubmissionTypes by GET /options"},"startDate":{"type":"object","required":["year","precision"],"properties":{"year":{"type":"string","pattern":"^[+-]?\\d+$","example":"1969"},"month":{"type":"integer","minimum":1,"maximum":12},"day":{"type":"integer","minimum":1,"maximum":31},"precision":{"enum":["year","month","day","circa","second"]}}},"tags":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"string"},"description":"New clean tags are accepted automatically. Three or more specific tags are preferred for discoverability; one remains valid."},"locationIds":{"type":"array","maxItems":12,"items":{"type":"string"}},"sources":{"type":"array","minItems":1,"maxItems":8,"items":{"$ref":"#/components/schemas/SourceInput"}},"reference":{"type":"string","format":"uri","deprecated":true,"description":"Legacy single-source field"},"duplicateOverride":{"type":"boolean","default":false}}},"SourceInput":{"oneOf":[{"type":"string","format":"uri"},{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"title":{"type":"string","maxLength":160}}}]},"OptionsResponse":{"type":"object","required":["types","acceptedSubmissionTypes","tags","tagPolicy","locations"],"properties":{"types":{"type":"array","description":"Types currently represented by published events","items":{"$ref":"#/components/schemas/CountedOption"}},"acceptedSubmissionTypes":{"type":"array","items":{"type":"string","enum":["birth","death","war","discovery","invention","political","politics","law","technology","economy","conflict","disaster","organization","science","religion","culture","society","personal","other"]}},"tags":{"type":"array","description":"Every approved or unmoderated tag attached to a searchable event","items":{"allOf":[{"$ref":"#/components/schemas/CountedOption"},{"type":"object","properties":{"moderationStatus":{"enum":["approved","unmoderated"]}}}]}},"tagPolicy":{"type":"object","required":["minimum","preferredMinimum","maximum","newTagsAllowed","newTagsSearchableImmediately"],"properties":{"minimum":{"const":1},"preferredMinimum":{"const":3},"maximum":{"const":20},"newTagsAllowed":{"const":true},"newTagsSearchableImmediately":{"const":true},"note":{"type":"string"}}},"locations":{"type":"array","items":{"type":"object","required":["id","name","kind"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"count":{"type":"integer"}}}}}},"CountedOption":{"type":"object","required":["value","count"],"properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":0}}}}}}