{"components":{"responses":{"InvalidDatasetQuery":{"description":"A parameter is unknown, blank, repeated, malformed, or unsupported; a filter is not available on this dataset; or a data.{key} name contains unsupported characters.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Unknown filter column \"provider\".","columns":["id","name","source","state","city"]}}}},"InvalidRowId":{"description":"The row id is not a valid School’s Out UUID, or the request includes a query parameter. Record lookup accepts path parameters only.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Field \"id\" must be the row uuid."}}}},"NoQueryParameters":{"description":"The facets endpoint received a query parameter. Facets are returned for the complete tier-visible dataset window and cannot be narrowed.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Unknown query parameter \"state\".","parameters":[]}}}},"InvalidSearchQuery":{"description":"q is missing, empty, too long, or provided more than five times; a parameter is unknown, blank, repeated, or malformed; or an exact filter is unavailable on the selected dataset.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Query parameter \"limit\" must be between 1 and 200."}}}},"SearchTimeout":{"description":"Search exceeded its five-second database limit. Narrow the request with dataset or an exact filter before retrying.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Search took too long. Narrow the query with a dataset or exact filter and try again."}}}},"SearchBusy":{"description":"Search capacity is busy. Wait one second before retrying.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","example":1}}},"content":{"application/json":{"example":{"data":null,"error":true,"message":"Search is busy. Try again in a moment.","retryAfterMs":1000}}}},"Unauthorized":{"description":"The x-api-key header is missing or the key is no longer valid.","content":{"application/json":{"example":{"authorized":false}}}},"PlanRequired":{"description":"The organization catalog requires Starter or above.","content":{"application/json":{"example":{"data":null,"error":true,"message":"The Data Explorer opens with Starter. Your Ask questions stay available on the Free plan.","upgradeRequired":true,"tier":"free","requiredTier":"paid","upgrade":"/api/billing/checkout"}}}},"Forbidden":{"description":"Your plan does not include the dataset, field, or result window.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Free accounts receive 403: the Data Explorer opens with the Starter plan.","upgradeRequired":true,"tier":"free","resultLimit":1}}}},"NotFound":{"description":"The dataset or row does not exist.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Unknown insights dataset."}}}},"ServerError":{"description":"The API failed while handling a valid request.","content":{"application/json":{"example":{"data":null,"error":true,"message":"Database request failed."}}}},"BookingsDisabled":{"description":"Bookings are off on this API (`BOOKINGS_ENABLED` isn’t `true`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"not found."}}}},"BookingNotFound":{"description":"No such booking for this parent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"Booking not found.","data":null}}}}},"schemas":{"AssistantEvidenceAssessment":{"additionalProperties":false,"description":"Assessment of the returned permission-filtered row. Coverage and aggregate organization metadata are not verification of free-text claims. Historical saved responses may predate this field.","properties":{"facts":{"additionalProperties":false,"properties":{"ages":{"additionalProperties":true,"properties":{"fields":{"items":{"type":"string"},"type":"array"},"state":{"enum":["present","partial","missing","unchecked"]},"unscopedFields":{"description":"Ambiguous bare shared columns in a joined row, excluded from this entity’s coverage.","items":{"type":"string"},"type":"array"}},"required":["state","fields"],"type":"object"},"availability":{"additionalProperties":true,"properties":{"currentPlacesConfirmed":{"const":false},"fields":{"items":{"type":"string"},"type":"array"},"state":{"enum":["present","partial","missing","unchecked"]},"unscopedFields":{"description":"Ambiguous bare shared columns in a joined row, excluded from this entity’s coverage.","items":{"type":"string"},"type":"array"}},"required":["state","fields"],"type":"object"},"hours":{"additionalProperties":true,"properties":{"fields":{"items":{"type":"string"},"type":"array"},"state":{"enum":["present","partial","missing","unchecked"]},"unscopedFields":{"description":"Ambiguous bare shared columns in a joined row, excluded from this entity’s coverage.","items":{"type":"string"},"type":"array"}},"required":["state","fields"],"type":"object"},"price":{"additionalProperties":true,"properties":{"budgetComparable":{"const":false},"currency":{"enum":["present","missing","unchecked"]},"fields":{"items":{"type":"string"},"type":"array"},"mandatoryFees":{"const":"unknown"},"period":{"const":"unknown"},"state":{"enum":["present","partial","missing","unchecked"]},"unscopedFields":{"description":"Ambiguous bare shared columns in a joined row, excluded from this entity’s coverage.","items":{"type":"string"},"type":"array"}},"required":["state","fields"],"type":"object"}},"required":["price","ages","hours","availability"],"type":"object"},"limitations":{"items":{"type":"string"},"type":"array"},"organization":{"additionalProperties":false,"properties":{"calculatedAt":{"description":"Score calculation time; never treated as source verification.","type":["string","null"]},"caps":{"items":{"type":"object"},"type":["array","null"]},"confidence":{"description":"Selected existing organization score; null when unavailable.","type":["number","null"]},"flags":{"items":{"type":"object"},"type":["array","null"]},"freshness":{"description":"Selected existing organization score; null when unavailable.","type":["number","null"]},"lastObservedAt":{"description":"Newest selected organization evidence date; not a fact-specific check.","type":["string","null"]},"missingFieldCount":{"type":["number","null"]},"scope":{"const":"organization"},"sourceCount":{"type":["number","null"]},"state":{"description":"Observed means an observation date was supplied, not that individual listing facts are fresh.","enum":["unknown","observed","stale"]}},"required":["scope","state","freshness","confidence","lastObservedAt","calculatedAt","caps","flags","sourceCount","missingFieldCount"],"type":"object"},"scope":{"description":"Entity whose selected facts are assessed. Parent and child fields do not fill each other’s gaps.","enum":["activity","session","listing"]}},"required":["scope","organization","facts","limitations"],"type":"object"},"CanonicalDetailRow":{"additionalProperties":true,"properties":{"after_care_pricing":{"$ref":"#/components/schemas/CarePricing","readOnly":true,"description":"Read-only compatibility quote when every prices option records the same after-care quote. Unknown when any option has unknown or different pricing. Edit the quote in prices."},"before_care_pricing":{"$ref":"#/components/schemas/CarePricing","readOnly":true,"description":"Read-only compatibility quote when every prices option records the same before-care quote. Unknown when any option has unknown or different pricing. Edit the quote in prices."},"registration_close_date":{"description":"Session-owned last date this session accepts registrations; it has no activity or organization fallback.","format":"date","type":"string"},"registration_open_date":{"description":"Session-owned first date this session accepts registrations; it has no activity or organization fallback.","format":"date","type":"string"},"schedule_configurations":{"description":"Authoritative attendance configurations using explicit dates or bounded weekly date_rule values. Omission means no structured schedule is available; empty arrays are invalid. The whole collection is one reversible contribution. Rules remain rules in storage and responses; derived bounds do not imply attendance on intervening dates. Pricing inside configurations follows the same access policy as other prices.","items":{"$ref":"#/components/schemas/SessionScheduleConfiguration"},"minItems":1,"type":"array"},"prices":{"description":"Ordered session enrollment options with optional source-grounded descriptions and before- and after-care quotes. A care-only option leaves tuition unknown. An empty array means no recorded price; the complete collection, including descriptions and care quotes, is one canonical field.","items":{"$ref":"#/components/schemas/SessionPrice"},"type":"array"},"resolved_cover":{"anyOf":[{"$ref":"#/components/schemas/CanonicalResolvedCover"},{"type":"null"}],"description":"Present on permitted ordinary JSON catalog reads, including includeMedia=false; omitted from previews and canonical SQL."}},"type":"object","description":"Sessions own registration_open_date, registration_close_date, an ordered prices collection, and nullable freeform `discounts` text; attendance dates and clocks belong to schedule_configurations. Activities have no enrollment price, currency, discount, or care-pricing fields. Activity image_url is a compatibility read alias for the selected active cover only. Each session price option may include a source-grounded description and before_care_pricing and after_care_pricing quotes; blank descriptions are omitted and no default label is inferred. Session-level care fields are read-only compatibility summaries when all options share a quote. Schedule configurations retain their own independent care quotes. Normal JSON records omit bookkeeping and ingestion history, null and blank record fields, and unknown availability, registration-status, and coordinate-precision values. Zero, false, empty arrays, masked values, positional range bounds, and structured schedule states retain their meanings. Related entity summaries follow the same projection; CSV and SQL retain their existing contracts. Moved fields are configuration_id, external_ids, created_at, updated_at, source_created_at, field_provenance, source_records, merge_jobs, and relationship_jobs. Age ranges use age_range_years; normal JSON records and column metadata omit the redundant age_range_months alias. CSV, SQL, and the legacy ageMonths filter retain month compatibility. Records omit score; fetch the separate score endpoints when needed."},"CanonicalFieldProvenance":{"additionalProperties":{"additionalProperties":false,"properties":{"history":{"description":"Newest decisions first; the first entry is the latest decision. Current owners and the latest observation may predate this bounded history.","items":{"$ref":"#/components/schemas/FieldProvenanceEntry"},"type":"array"},"latest_observation":{"$ref":"#/components/schemas/FieldProvenanceEntry"},"sources":{"items":{"$ref":"#/components/schemas/FieldProvenanceEntry"},"type":"array"},"state":{"description":"tracked means complete current-value coverage; partial means some range endpoints or supporting links have coverage; unknown has no current source owner.","enum":["tracked","partial","unknown"],"type":"string"},"value_state":{"description":"Current accepted field action, independent of whether a source check ran.","enum":["set","cleared","unknown"],"type":"string"}},"required":["state","sources","value_state"],"type":"object"},"description":"Present only for ADMIN user-backed reads of the dedicated provenance endpoint. Keys are visible display columns before sparse projection, including unset fields. state and sources describe current accepted-value ownership; value_state records whether the accepted value is set, cleared, or unknown. latest_observation and decision history are separate: checked_not_found, not_applicable, failed, and incomplete do not clear a value. No observation means no check was recorded. Older contributions are read without inferred checks. Field citations are distinct from a website scrape root, whose scope is site.","type":"object"},"ProvenanceTimelineOrganizationScore":{"description":"On-demand parent organization score with the currently deployed rubric. This is reconstructed data valuation, not an immutable originally served score. Missing historical inputs use rubric defaults and are disclosed; no current score is substituted.","oneOf":[{"type":"object","required":["state"],"properties":{"state":{"const":"restricted"}},"additionalProperties":false},{"type":"object","required":["state","evaluatedAt","scoringVersion","reason"],"properties":{"state":{"const":"unavailable"},"evaluatedAt":{"type":"string","format":"date-time","description":"Inclusive reconstruction cutoff, identical to entry recorded_at; rubric evaluation uses this time."},"scoringVersion":{"type":"string"},"reason":{"type":"string"}}},{"type":"object","required":["state","evaluatedAt","scoringVersion","overall","band","confidence","interval","caps","sourceCount","coverage"],"properties":{"state":{"const":"reconstructed"},"evaluatedAt":{"type":"string","format":"date-time","description":"Inclusive reconstruction cutoff, identical to entry recorded_at; rubric evaluation uses this time."},"scoringVersion":{"type":"string"},"overall":{"type":"number","minimum":0,"maximum":100},"band":{"enum":["weak","fair","good","strong"]},"confidence":{"type":"number","minimum":0,"maximum":100},"interval":{"type":"object","required":["low","high"],"properties":{"low":{"type":"number","minimum":0,"maximum":100},"high":{"type":"number","minimum":0,"maximum":100}}},"caps":{"type":"array","items":{"type":"object","required":["criterion","ceiling","reason"],"properties":{"criterion":{"type":"string"},"ceiling":{"type":"number","minimum":0,"maximum":100},"reason":{"type":"string"}}}},"sourceCount":{"type":"integer","minimum":0},"coverage":{"type":"object","required":["history","children","missingInputs"],"properties":{"history":{"const":"retained_canonical_contributions"},"children":{"const":"current_associations"},"missingInputs":{"type":"array","items":{"type":"string"},"description":"Machine-readable reconstruction limitations; clients must tolerate new codes."},"fallbackFields":{"type":"array","items":{"type":"string"},"description":"Qualified fields using current canonical values as an approximate baseline because no accepted history is retained for that field at any time."}}}}}]},"ProvenanceTimelineValue":{"description":"One before or after side. Only the available state carries a value; value accepts any JSON value, including explicit null. For media fields, an available value is an array of ProvenanceTimelineMediaItem, with no source attribution; an empty array means known empty.","oneOf":[{"additionalProperties":false,"properties":{"state":{"const":"available"},"value":{}},"required":["state","value"],"type":"object"},{"additionalProperties":false,"properties":{"state":{"const":"unavailable"}},"required":["state"],"type":"object"},{"additionalProperties":false,"properties":{"state":{"const":"restricted"}},"required":["state"],"type":"object"}]},"ProvenanceTimelineMediaItem":{"additionalProperties":false,"description":"Sanitized media page item in reconstructed timeline values. It contains no source or evidence provenance. Remote displayUrl values preserve signed query strings and fragments; same-entity uploads use the protected organization asset URL. Public stock credit is retained independently of private source evidence.","properties":{"displayUrl":{"format":"uri-reference","type":"string"},"height":{"type":["integer","null"]},"id":{"format":"uuid","type":"string"},"kind":{"type":"string"},"label":{"type":"string"},"width":{"type":["integer","null"]},"isStock":{"type":"boolean","description":"Derived from retained stock metadata."},"stock":{"anyOf":[{"$ref":"#/components/schemas/CanonicalStockImage"},{"type":"null"}]}},"required":["id","displayUrl","label","kind","width","height","isStock","stock"],"type":"object"},"CanonicalMediaItem":{"properties":{"displayUrl":{"description":"Original remote URL or a protected relative organization brand-asset URL.","format":"uri-reference","type":"string"},"height":{"minimum":1,"type":["integer","null"]},"id":{"format":"uuid","type":"string"},"kind":{"type":"string"},"label":{"type":"string"},"source":{"description":"Present only for a non-preview ADMIN account viewer.","items":{"$ref":"#/components/schemas/CanonicalMediaSource"},"type":"array"},"width":{"minimum":1,"type":["integer","null"]},"isStock":{"type":"boolean","description":"Derived from retained stock metadata."},"stock":{"anyOf":[{"$ref":"#/components/schemas/CanonicalStockImage"},{"type":"null"}]}},"required":["id","displayUrl","label","kind","isStock","stock"],"type":"object"},"CanonicalMediaPage":{"type":"object","description":"Exact-owner gallery page with independent resolvedCover for display. Borrowed covers retain sourceEntity and do not alter items, selected IDs or total. Stock credits are visible with the image; source evidence remains ADMIN-only.","properties":{"entity":{"type":"object","properties":{"kind":{"type":"string","enum":["organization","activity","session"]},"id":{"type":"string","format":"uuid"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalMediaItem"}},"coverId":{"type":["string","null"],"format":"uuid"},"logoId":{"type":["string","null"],"format":"uuid"},"total":{"type":"integer","minimum":0,"description":"Total number of visible distinct images."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum number of images in this page."},"offset":{"type":"integer","minimum":0,"description":"Zero-based offset of this page; bundled detail starts at zero."},"resolvedCover":{"anyOf":[{"$ref":"#/components/schemas/CanonicalResolvedCover"},{"type":"null"}]}},"required":["entity","items","coverId","logoId","resolvedCover","total","limit","offset"]},"CanonicalMediaSource":{"properties":{"baseline":{"type":"boolean"},"observedAt":{"format":"date-time","type":"string"},"source":{"properties":{"kind":{"enum":["trident","manual","legacy","upload"],"type":"string"},"recordId":{"type":"string"},"website":{"format":"uri","type":"string"}},"required":["kind"],"type":"object"},"sourcePageUrl":{"format":"uri","type":"string"}},"type":"object"},"CanonicalReference":{"description":"Staff metadata only: live PostgreSQL storage structure, application field definitions, and editing and interpretation rules. No entity record values. Coverage issues identify drift or missing explanations; a successful response with issues is not a fully described model.","properties":{"applicationFingerprint":{"type":"string"},"coverageIssues":{"items":{"$ref":"#/components/schemas/CanonicalReferenceCoverageIssue"},"type":"array"},"entities":{"items":{"$ref":"#/components/schemas/CanonicalReferenceEntity"},"type":"array"},"generatedAt":{"format":"date-time","type":"string"},"relationships":{"items":{"$ref":"#/components/schemas/CanonicalReferenceRelationship"},"type":"array"},"rules":{"items":{"$ref":"#/components/schemas/CanonicalReferenceRule"},"type":"array"},"schemaFingerprint":{"type":"string"},"version":{"const":1,"type":"integer"}},"required":["version","generatedAt","schemaFingerprint","applicationFingerprint","entities","relationships","rules","coverageIssues"],"type":"object"},"CanonicalReferenceConstraint":{"properties":{"columns":{"items":{"type":"string"},"type":"array"},"definition":{"type":"string"},"name":{"type":"string"},"referencedColumns":{"items":{"type":"string"},"type":"array"},"referencedSchema":{"type":"string"},"referencedTable":{"type":"string"},"type":{"type":"string"}},"required":["name","type","definition","columns"],"type":"object"},"CanonicalReferenceCoverageIssue":{"properties":{"code":{"type":"string"},"entity":{"type":"string"},"field":{"type":"string"},"message":{"type":"string"}},"required":["entity","field","code","message"],"type":"object"},"CanonicalReferenceEditor":{"properties":{"inputType":{"type":"string"},"key":{"type":"string"},"max":{"type":"number"},"maxItems":{"type":"integer"},"maxLength":{"type":"integer"},"min":{"type":"number"},"options":{"items":{"$ref":"#/components/schemas/CanonicalReferenceOption"},"type":"array"},"required":{"type":"boolean"},"staffOnly":{"type":"boolean"},"step":{"type":"number"},"supportedBits":{"items":{"$ref":"#/components/schemas/CanonicalReferenceOption"},"type":"array"}},"required":["key","required","inputType","options","staffOnly"],"type":"object"},"CanonicalReferenceEntity":{"properties":{"description":{"type":"string"},"fields":{"items":{"$ref":"#/components/schemas/CanonicalReferenceField"},"type":"array"},"kind":{"type":"string"},"label":{"type":"string"},"table":{"type":"string"}},"required":["kind","label","description","table","fields"],"type":"object"},"CanonicalReferenceField":{"properties":{"aliasOf":{"type":"string"},"dataType":{"description":"Type of the API or editing value; storage-only entries use the database type. A JSON read representation does not imply a physical JSON column. Sources and storage describe the underlying tables and columns.","type":"string"},"description":{"type":"string"},"editor":{"$ref":"#/components/schemas/CanonicalReferenceEditor"},"group":{"type":"string"},"id":{"type":"string"},"kind":{"enum":["stored","derived","editing","compatibility","storage"],"type":"string"},"label":{"type":"string"},"meaningSource":{"type":"string"},"name":{"type":"string"},"nullable":{"type":"boolean"},"sources":{"items":{"$ref":"#/components/schemas/CanonicalReferenceSource"},"type":"array"},"storage":{"items":{"$ref":"#/components/schemas/CanonicalReferenceStorage"},"type":"array"}},"required":["id","name","label","description","group","dataType","kind","nullable","sources","storage","meaningSource"],"type":"object"},"CanonicalReferenceOption":{"properties":{"label":{"type":"string"},"value":{}},"required":["value","label"],"type":"object"},"CanonicalReferenceRelationship":{"properties":{"field":{"type":"string"},"from":{"type":"string"},"label":{"type":"string"},"nullable":{"type":"boolean"},"to":{"type":"string"}},"required":["from","to","field","label","nullable"],"type":"object"},"CanonicalReferenceRule":{"properties":{"category":{"enum":["editing","interpretation"],"type":"string"},"description":{"type":"string"},"details":{"additionalProperties":true,"type":"object"},"entities":{"items":{"type":"string"},"type":"array"},"fields":{"items":{"type":"string"},"type":"array"},"id":{"type":"string"},"label":{"type":"string"},"source":{"type":"string"}},"required":["id","category","label","description","entities","fields","source"],"type":"object"},"CanonicalReferenceSource":{"properties":{"column":{"type":"string"},"table":{"type":"string"}},"required":["table","column"],"type":"object"},"CanonicalReferenceStorage":{"properties":{"column":{"type":"string"},"comment":{"type":"string"},"constraints":{"items":{"$ref":"#/components/schemas/CanonicalReferenceConstraint"},"type":"array"},"dataType":{"type":"string"},"default":{"type":["string","null"]},"enumValues":{"items":{"type":"string"},"type":"array"},"generated":{"type":"string"},"identity":{"type":"string"},"nullable":{"type":"boolean"},"primaryKey":{"type":"boolean"},"table":{"type":"string"}},"required":["table","column","dataType","nullable","default","comment","primaryKey","constraints","enumValues"],"type":"object"},"CarePricing":{"additionalProperties":false,"description":"One coherent before- or after-care quote; null means price unknown. Amount zero means explicitly free care. The quote is selected and reversed with its owning prices or schedule_configurations collection.","properties":{"amount":{"description":"Amount in major currency units, such as dollars rather than cents.","minimum":0,"type":"number"},"basis":{"description":"Stated price rate. session covers the entire enrollment; null means the rate is unknown. Never inferred from a price.","enum":["hour","day","week","month","session",null],"type":["string","null"]},"currency":{"description":"Three-letter currency code for this care quote, independent of tuition currency.","pattern":"^[A-Za-z]{3}$","type":"string"}},"required":["amount","currency"],"type":["object","null"]},"ChildGuardian":{"properties":{"email":{"type":"string"},"joinedAt":{"format":"date-time","type":"string"},"userId":{"format":"uuid","type":"string"}},"required":["userId","email","joinedAt"],"type":"object"},"ChildInvitation":{"properties":{"createdAt":{"format":"date-time","type":"string"},"email":{"format":"email","type":"string"},"expiresAt":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"}},"required":["id","email","createdAt","expiresAt"],"type":"object"},"ChildInvitationPreview":{"allOf":[{"$ref":"#/components/schemas/ChildInvitation"},{"properties":{"childId":{"format":"uuid","type":"string"},"childName":{"type":"string"},"invitedByEmail":{"type":"string"}},"required":["childId","childName","invitedByEmail"],"type":"object"}]},"Collection":{"additionalProperties":false,"properties":{"archivedAt":{"format":"date-time","type":["string","null"]},"availableMemberCount":{"description":"Nondeleted and nonblacklisted member camps currently available in the catalog.","minimum":0,"type":"integer"},"createdAt":{"format":"date-time","type":"string"},"createdBy":{"description":"Null when the account that created the shared collection has been deleted; the collection and memberships remain.","format":"uuid","type":["string","null"]},"id":{"format":"uuid","type":"string"},"memberCount":{"description":"All retained camp memberships, including currently unavailable camps.","minimum":0,"type":"integer"},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","name","createdBy","createdAt","updatedAt","archivedAt","memberCount","availableMemberCount"],"type":"object"},"CollectionInput":{"additionalProperties":false,"properties":{"name":{"description":"Single-line collection name. Active names are unique without regard to case.","maxLength":120,"minLength":1,"type":"string"}},"required":["name"],"type":"object"},"CollectionUpdateInput":{"additionalProperties":false,"minProperties":1,"properties":{"archived":{"const":true,"description":"Archive the collection; archive is permanent."},"name":{"maxLength":120,"minLength":1,"type":"string"}},"type":"object"},"CoordinatePrecision":{"description":"Source quality, independent of numeric precision. Accessible coordinates retain full stored precision on every plan, without a guarantee of geographic correctness. exact covers complete existing/source pairs under the scraper-data assumption. null means no complete pair. ZIP representative points may lack a boundary.","enum":["exact","building","parcel","street","zip","state","unknown",null],"type":["string","null"]},"CrawlerEvaluation":{"additionalProperties":false,"properties":{"attempt_id":{"type":["string","null"],"description":"Execution attempt for this evaluation; distinct from source_attempt_id."},"baseline_evaluation_id":{"type":["string","null"]},"completion_reason":{"type":["string","null"]},"config":{"$ref":"#/components/schemas/CrawlerConfig"},"counts":{"$ref":"#/components/schemas/CrawlerEvaluationCounts"},"created_at":{"format":"date-time","type":"string"},"finished_at":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"idempotency_key":{"type":["string","null"],"description":"Immutable job-scoped Trident retry key."},"job_id":{"type":"string"},"kind":{"type":"string","enum":["original","rejudge","site_vetting"]},"purpose":{"type":"string","enum":["url_relevance","trident_summer_camp"]},"source_attempt_id":{"type":["string","null"],"description":"Immutable source crawl provenance for site_vetting."},"status":{"type":"string","enum":["queued","running","completed","partial","failed","cancelled"]}},"required":["attempt_id","baseline_evaluation_id","completion_reason","config","counts","created_at","finished_at","id","idempotency_key","job_id","kind","purpose","source_attempt_id","status"],"type":"object"},"FamilyApprovalSource":{"additionalProperties":false,"description":"The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","properties":{"conversationId":{"format":"uuid","type":"string"},"turnId":{"format":"uuid","type":"string"},"type":{"enum":["manual","assistant"]}},"required":["type"],"type":"object"},"FamilyArea":{"additionalProperties":false,"properties":{"label":{"maxLength":120,"minLength":1,"type":"string"},"postalCode":{"pattern":"^[0-9]{5}$","type":"string"},"region":{"pattern":"^[A-Z]{2}$","type":"string"}},"required":["label"],"type":"object"},"FamilyBudget":{"additionalProperties":false,"properties":{"amount":{"description":"At most two decimal places.","maximum":1000000,"minimum":0,"type":"number"},"currency":{"pattern":"^[A-Z]{3}$","type":"string"},"limit":{"enum":["hard_cap","preference"]},"period":{"enum":["day","week","month","session","season","year","total"]},"scope":{"enum":["per_child","household"]}},"required":["amount","currency","period","scope","limit"],"type":"object"},"FamilyCareRequirement":{"properties":{"childIds":{"description":"Only children the owner can currently access; revocation and deletion remove them.","items":{"format":"uuid","type":"string"},"type":"array"},"createdAt":{"format":"date-time","type":"string"},"details":{"additionalProperties":false,"properties":{"budget":{"$ref":"#/components/schemas/FamilyBudget"},"coverage":{"additionalProperties":false,"properties":{"minimumDaysPerWeek":{"maximum":7,"minimum":1,"type":"integer"},"mode":{"enum":["every_required_day","partial_ok"]}},"required":["mode"],"type":"object"},"dates":{"additionalProperties":false,"description":"Either an inclusive start/end range of at most one year, or 1-60 explicit dates.","properties":{"dates":{"items":{"format":"date","type":"string"},"maxItems":60,"type":"array"},"end":{"format":"date","type":"string"},"start":{"format":"date","type":"string"}},"type":"object"},"days":{"description":"Required for a range; not allowed with explicit dates.","items":{"enum":["mon","tue","wed","thu","fri","sat","sun"]},"minItems":1,"type":"array"},"exceptions":{"items":{"additionalProperties":false,"properties":{"date":{"format":"date","type":"string"},"hours":{"$ref":"#/components/schemas/FamilyTimeRange"},"needed":{"type":"boolean"}},"required":["date","needed"],"type":"object"},"maxItems":60,"type":"array"},"flexibility":{"additionalProperties":false,"properties":{"endMinutes":{"maximum":180,"minimum":0,"type":"integer"},"level":{"enum":["fixed","flexible"]},"startMinutes":{"maximum":180,"minimum":0,"type":"integer"}},"required":["level"],"type":"object"},"hours":{"$ref":"#/components/schemas/FamilyTimeRange"},"label":{"maxLength":80,"type":"string"},"recurrence":{"additionalProperties":false,"properties":{"intervalWeeks":{"enum":[1,2]}},"required":["intervalWeeks"],"type":"object"},"timezone":{"description":"IANA zone; defaults to the household time zone.","type":"string"},"travel":{"$ref":"#/components/schemas/FamilyTravel"}},"required":["dates","hours","flexibility","coverage"],"type":"object"},"id":{"format":"uuid","type":"string"},"provenance":{"additionalProperties":{"$ref":"#/components/schemas/FamilyProvenance"},"type":"object"},"updatedAt":{"format":"date-time","type":"string"},"version":{"type":"integer"}},"required":["id","version","childIds","details","provenance","createdAt","updatedAt"],"type":"object"},"FamilyCareRequirementInput":{"allOf":[{"additionalProperties":false,"properties":{"budget":{"$ref":"#/components/schemas/FamilyBudget"},"coverage":{"additionalProperties":false,"properties":{"minimumDaysPerWeek":{"maximum":7,"minimum":1,"type":"integer"},"mode":{"enum":["every_required_day","partial_ok"]}},"required":["mode"],"type":"object"},"dates":{"additionalProperties":false,"description":"Either an inclusive start/end range of at most one year, or 1-60 explicit dates.","properties":{"dates":{"items":{"format":"date","type":"string"},"maxItems":60,"type":"array"},"end":{"format":"date","type":"string"},"start":{"format":"date","type":"string"}},"type":"object"},"days":{"description":"Required for a range; not allowed with explicit dates.","items":{"enum":["mon","tue","wed","thu","fri","sat","sun"]},"minItems":1,"type":"array"},"exceptions":{"items":{"additionalProperties":false,"properties":{"date":{"format":"date","type":"string"},"hours":{"$ref":"#/components/schemas/FamilyTimeRange"},"needed":{"type":"boolean"}},"required":["date","needed"],"type":"object"},"maxItems":60,"type":"array"},"flexibility":{"additionalProperties":false,"properties":{"endMinutes":{"maximum":180,"minimum":0,"type":"integer"},"level":{"enum":["fixed","flexible"]},"startMinutes":{"maximum":180,"minimum":0,"type":"integer"}},"required":["level"],"type":"object"},"hours":{"$ref":"#/components/schemas/FamilyTimeRange"},"label":{"maxLength":80,"type":"string"},"recurrence":{"additionalProperties":false,"properties":{"intervalWeeks":{"enum":[1,2]}},"required":["intervalWeeks"],"type":"object"},"timezone":{"description":"IANA zone; defaults to the household time zone.","type":"string"},"travel":{"$ref":"#/components/schemas/FamilyTravel"}},"required":["dates","hours","flexibility","coverage"],"type":"object"},{"properties":{"childIds":{"items":{"format":"uuid","type":"string"},"maxItems":10,"minItems":1,"type":"array"},"source":{"$ref":"#/components/schemas/FamilyApprovalSource"}},"required":["childIds"],"type":"object"}]},"FamilyChildFields":{"additionalProperties":false,"description":"Optional registration fields. A planning label can identify a profile without full names; enabling registration reuse requires both child.firstName and child.lastName.","properties":{"child.allergies":{"maxLength":4000,"type":"string"},"child.birthDate":{"maxLength":10,"type":"string"},"child.firstName":{"maxLength":255,"type":"string"},"child.grade":{"maxLength":100,"type":"string"},"child.lastName":{"maxLength":255,"type":"string"},"child.notes":{"maxLength":4000,"type":"string"},"emergencyContact.name":{"maxLength":255,"type":"string"},"emergencyContact.phone":{"maxLength":64,"type":"string"},"guardian.email":{"maxLength":254,"type":"string"},"guardian.name":{"maxLength":255,"type":"string"},"guardian.phone":{"maxLength":64,"type":"string"},"guardian.relationship":{"maxLength":255,"type":"string"},"secondaryGuardian.email":{"maxLength":254,"type":"string"},"secondaryGuardian.name":{"maxLength":255,"type":"string"},"secondaryGuardian.phone":{"maxLength":64,"type":"string"}},"type":"object"},"FamilyChildInput":{"additionalProperties":false,"description":"A new profile needs a nonempty planning label or both first and last names. Registration reuse requires both names. PUT replaces fields and preferences; when planning is omitted, existing planning values are retained and the merged profile must still have a label or full name.","properties":{"fields":{"$ref":"#/components/schemas/FamilyChildFields"},"planning":{"$ref":"#/components/schemas/FamilyChildPlanning"},"preferences":{"$ref":"#/components/schemas/FamilyChildPreferences"},"reuseAllowed":{"default":false,"type":"boolean"},"source":{"$ref":"#/components/schemas/FamilyApprovalSource"},"version":{"minimum":1,"type":"integer"}},"required":["fields"],"type":"object"},"FamilyChildPlanning":{"additionalProperties":false,"description":"Enduring planning details registration forms do not use. A label alone can start a profile; registration reuse still needs first and last names. Save a date of birth or an age with its as-of date, not both. Nothing is inferred.","properties":{"age":{"additionalProperties":false,"properties":{"asOf":{"format":"date","type":"string"},"years":{"maximum":21,"minimum":0,"type":"integer"}},"required":["years","asOf"],"type":"object"},"gradeSchoolYear":{"description":"The school year fields[\"child.grade\"] applies to, such as 2026-2027.","pattern":"^[0-9]{4}-[0-9]{4}$","type":"string"},"label":{"maxLength":60,"type":"string"},"requirements":{"items":{"additionalProperties":false,"properties":{"category":{"enum":["health_safety","dietary","accessibility","supervision","communication","social","other"]},"detail":{"description":"A practical parent-stated condition; no diagnosis is needed.","maxLength":300,"minLength":1,"type":"string"},"kind":{"enum":["required","preference"]}},"required":["kind","category","detail"],"type":"object"},"maxItems":20,"type":"array"},"requirementsStatus":{"enum":["unknown","none","listed"]}},"type":"object"},"FamilyChildPreferences":{"additionalProperties":false,"properties":{"interests":{"items":{"maxLength":100,"type":"string"},"maxItems":20,"type":"array"},"interestsStatus":{"description":"unknown means the parent has not answered; none means no interests; listed requires interests. Omitted, it is listed when interests are present and otherwise unknown.","enum":["unknown","none","listed"]},"notes":{"maxLength":2000,"type":"string"}},"type":"object"},"FamilyChildProfile":{"properties":{"createdAt":{"format":"date-time","type":"string"},"fields":{"$ref":"#/components/schemas/FamilyChildFields"},"id":{"format":"uuid","type":"string"},"planning":{"$ref":"#/components/schemas/FamilyChildPlanning"},"preferences":{"$ref":"#/components/schemas/FamilyChildPreferences"},"provenance":{"additionalProperties":{"$ref":"#/components/schemas/FamilyProvenance"},"description":"Current-value approval for saved registration fields, preferences and planning values. Removed values leave no entry; unchanged values keep their provenance. Another adult's conversation reference is omitted.","type":"object"},"reuseAllowed":{"type":"boolean"},"role":{"description":"Owner controls invitations, deletion and reuse permission. Guardians may correct fields/preferences and use already-enabled reuse.","enum":["owner","guardian"],"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"version":{"minimum":1,"type":"integer"}},"required":["id","version","fields","preferences","reuseAllowed","provenance","createdAt","updatedAt","role","planning"],"type":"object"},"FamilyCorrection":{"additionalProperties":false,"description":"Narrow correction: each named key replaces its value and null removes it. Unnamed values and their approvals are unchanged. The merged record is validated like a complete submission. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","properties":{"changes":{"minProperties":1,"type":"object"},"source":{"$ref":"#/components/schemas/FamilyApprovalSource"},"version":{"minimum":0,"type":"integer"}},"required":["version","changes"],"type":"object"},"FamilyHousehold":{"properties":{"preferences":{"$ref":"#/components/schemas/FamilyHouseholdPreferences"},"provenance":{"additionalProperties":{"$ref":"#/components/schemas/FamilyProvenance"},"type":"object"},"updatedAt":{"format":"date-time","type":["string","null"]},"version":{"description":"0 when nothing is saved.","type":"integer"}},"required":["version","preferences","provenance","updatedAt"],"type":"object"},"FamilyHouseholdPreferences":{"additionalProperties":false,"properties":{"budget":{"$ref":"#/components/schemas/FamilyBudget"},"caregiverAvailability":{"additionalProperties":false,"description":"Recurring windows when a caregiver is available, date exceptions that replace them, and the times a caregiver can drop off or pick up.","properties":{"dropoff":{"$ref":"#/components/schemas/FamilyTimeRange"},"exceptions":{"items":{"additionalProperties":false,"properties":{"available":{"type":"boolean"},"date":{"format":"date","type":"string"},"hours":{"$ref":"#/components/schemas/FamilyTimeRange"}},"required":["date","available"],"type":"object"},"maxItems":60,"type":"array"},"pickup":{"$ref":"#/components/schemas/FamilyTimeRange"},"windows":{"items":{"additionalProperties":false,"properties":{"days":{"items":{"enum":["mon","tue","wed","thu","fri","sat","sun"]},"minItems":1,"type":"array"},"end":{"type":"string"},"start":{"type":"string"}},"required":["days","start","end"],"type":"object"},"maxItems":14,"type":"array"}},"type":"object"},"searchArea":{"$ref":"#/components/schemas/FamilyArea"},"timezone":{"description":"IANA time zone, such as America/Los_Angeles.","type":"string"},"travel":{"$ref":"#/components/schemas/FamilyTravel"}},"type":"object"},"FamilyMemoryFact":{"properties":{"category":{"enum":["activity_history","logistics","preference","other"]},"childId":{"format":"uuid","type":["string","null"]},"createdAt":{"format":"date-time","type":"string"},"expiresOn":{"format":"date","type":["string","null"]},"id":{"format":"uuid","type":"string"},"provenance":{"$ref":"#/components/schemas/FamilyProvenance"},"sourceReference":{"description":"Cleared when that conversation is deleted.","type":["object","null"]},"statement":{"maxLength":500,"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"version":{"type":"integer"}},"required":["id","version","childId","category","statement","expiresOn","provenance","sourceReference"],"type":"object"},"FamilyProvenance":{"description":"Approval of the current value only. Another adult's sourceReference is never returned; removed values leave no entry.","properties":{"actorId":{"format":"uuid","type":"string"},"approvedAt":{"format":"date-time","type":"string"},"source":{"enum":["manual","assistant"]},"sourceReference":{"properties":{"conversationId":{"format":"uuid","type":"string"},"turnId":{"format":"uuid","type":"string"}},"type":"object"},"version":{"description":"Record version at which this value was approved or reconfirmed.","type":"integer"}},"required":["source","actorId","approvedAt"],"type":"object"},"FamilyReconfirmation":{"additionalProperties":false,"description":"Records a fresh approval of unchanged current values and advances the record version. A key without a saved value returns 409.","properties":{"keys":{"items":{"type":"string"},"maxItems":40,"minItems":1,"type":"array"},"source":{"$ref":"#/components/schemas/FamilyApprovalSource"},"version":{"minimum":1,"type":"integer"}},"required":["version","keys"],"type":"object"},"FamilyTimeRange":{"additionalProperties":false,"properties":{"end":{"pattern":"^[0-2][0-9]:[0-5][0-9]$","type":"string"},"start":{"pattern":"^[0-2][0-9]:[0-5][0-9]$","type":"string"}},"required":["start","end"],"type":"object"},"FamilyTravel":{"additionalProperties":false,"description":"Needs maxMinutes or maxDistance. Without origin, travel is measured from the search area.","properties":{"limit":{"enum":["hard_cap","preference"]},"maxDistance":{"additionalProperties":false,"properties":{"unit":{"enum":["mi","km"]},"value":{"exclusiveMinimum":0,"maximum":500,"type":"number"}},"required":["value","unit"],"type":"object"},"maxMinutes":{"maximum":240,"minimum":1,"type":"integer"},"mode":{"enum":["driving","transit","walking","cycling"]},"origin":{"$ref":"#/components/schemas/FamilyArea"}},"required":["mode","limit"],"type":"object"},"FieldProvenanceEntry":{"additionalProperties":false,"description":"One provenance record shared by current sources, the latest observation, and decision history. Older source-only records may omit decision fields.","properties":{"action":{"enum":["keep","set","clear"],"type":"string"},"authority":{"enum":["automated","human"],"type":"string"},"batch_id":{"format":"uuid","type":"string"},"evidence":{"items":{"$ref":"#/components/schemas/FieldProvenanceEvidence"},"type":"array"},"field":{"description":"Canonical field or range endpoint described by this record.","type":"string"},"kind":{"enum":["scrape","manual_update","overseer","import","other"],"type":"string"},"label":{"description":"Fixed category label; submitter identities and personal batch names are omitted.","type":"string"},"observation":{"enum":["found","checked_not_found","not_applicable","failed","incomplete"],"type":"string"},"observed_at":{"format":"date-time","type":"string"},"reason":{"type":"string"},"recorded_at":{"description":"Contribution recording time, not source verification time.","format":"date-time","type":"string"},"review_id":{"format":"uuid","type":"string"},"review_version":{"minimum":1,"type":"integer"},"rule":{"type":"string"},"source_url":{"description":"Validated retained website-scrape root. The root does not cite an individual field.","format":"uri","type":"string"},"source_url_scope":{"enum":["site"],"type":"string"}},"required":["kind","label"],"type":"object"},"FieldProvenanceEvidence":{"additionalProperties":false,"properties":{"captured_at":{"format":"date-time","type":"string"},"quote":{"type":"string"},"url":{"description":"Validated HTTP(S) field citation or captured-page URL, without userinfo, query, or fragment.","format":"uri","type":"string"}},"required":["url"],"type":"object"},"GeocodingCoverage":{"properties":{"affectedRecords":{"description":"Live entity references to locations in scope.","minimum":0,"type":"integer"},"applicableLocations":{"description":"Locations eligible for US reference derivation.","minimum":0,"type":"integer"},"missingBoundaries":{"description":"Approximate locations lacking a boundary.","minimum":0,"type":"integer"},"missingCoordinates":{"description":"Locations lacking a complete pair.","minimum":0,"type":"integer"},"pending":{"description":"Locations awaiting automatic work.","minimum":0,"type":"integer"},"precision":{"additionalProperties":{"minimum":0,"type":"integer"},"type":"object"},"reference":{"properties":{"available":{"type":"boolean"},"source":{"type":"string"},"version":{"type":"string"}},"type":"object"},"scope":{"properties":{"city":{"description":"Optional recorded address label, not a city polygon.","type":"string"},"postalCode":{"description":"Optional US ZIP or ZIP+4; normalized to five digits.","type":"string"},"state":{"description":"US state name or code; normalized to the two-letter code.","type":"string"}},"type":"object"},"totalLocations":{"description":"Distinct live configurations in scope.","minimum":0,"type":"integer"},"unresolved":{"description":"Locations with unresolved automatic derivations.","minimum":0,"type":"integer"},"worker":{"properties":{"error":{"type":"string"},"geocodioConfigured":{"type":"boolean"},"lastSeenAt":{"format":"date-time","type":"string"},"status":{"type":"string"}},"type":"object"},"zipMatched":{"description":"Locations matched to ZIP reference data.","minimum":0,"type":"integer"},"zipPopulated":{"description":"Locations with a populated ZIP.","minimum":0,"type":"integer"},"zipValid":{"description":"Locations with a recognized valid ZIP.","minimum":0,"type":"integer"}},"type":"object"},"GeocodingItem":{"properties":{"address":{"description":"Staff-only snapshot of the requested address.","type":"string"},"configurationId":{"format":"uuid","type":"string"},"error":{"type":"string"},"id":{"format":"uuid","type":"string"},"precision":{"$ref":"#/components/schemas/CoordinatePrecision"},"status":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","configurationId","status","address","updatedAt"],"type":"object"},"GeocodingJob":{"allOf":[{"$ref":"#/components/schemas/GeocodingPreview"},{"properties":{"cancelled":{"description":"Items cancelled before submission.","minimum":0,"type":"integer"},"completedAt":{"format":"date-time","type":"string"},"createdAt":{"format":"date-time","type":"string"},"error":{"type":"string"},"failed":{"description":"Failed items.","minimum":0,"type":"integer"},"id":{"format":"uuid","type":"string"},"processed":{"description":"Items with settled outcomes.","minimum":0,"type":"integer"},"requestedBy":{"type":"string"},"stale":{"description":"Items changed since the confirmed snapshot.","minimum":0,"type":"integer"},"startedAt":{"format":"date-time","type":"string"},"status":{"description":"Persisted job lifecycle status. Uncertain provider submissions require reconciliation before replacement work.","type":"string"},"submittedLookups":{"description":"Provider lookups already submitted against the frozen budget.","minimum":0,"type":"integer"},"succeeded":{"description":"Items with accepted coordinates.","minimum":0,"type":"integer"},"unresolved":{"description":"Items without an acceptable result.","minimum":0,"type":"integer"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","status","requestedBy","createdAt","updatedAt","submittedLookups","processed","succeeded","unresolved","failed","stale","cancelled"],"type":"object"}]},"GeocodingPreview":{"allOf":[{"$ref":"#/components/schemas/GeocodingPreviewInput"},{"properties":{"affectedRecords":{"description":"Live organizations, activities, and sessions referencing the eligible configurations.","minimum":0,"type":"integer"},"configurations":{"description":"Distinct eligible live configurations. Shared configurations count once.","minimum":0,"type":"integer"},"estimatedCostMicrousd":{"description":"Estimated cost in millionths of a US dollar, before shared free credits.","minimum":0,"type":"integer"},"exclusions":{"additionalProperties":{"minimum":0,"type":"integer"},"description":"Excluded location counts by reason.","type":"object"},"fingerprint":{"description":"Quote fingerprint; must match recomputed eligibility and pricing at confirmation.","type":"string"},"requiredLookups":{"description":"Maximum new provider lookups covered by this quote.","minimum":0,"type":"integer"},"reusedAddresses":{"description":"Addresses with reusable successful results in gap mode.","minimum":0,"type":"integer"},"uniqueAddresses":{"description":"Distinct normalized eligible addresses.","minimum":0,"type":"integer"},"unitPriceMicrousd":{"description":"Price in millionths of a US dollar per lookup. Initially 1000 ($1 per 1000 lookups).","minimum":0,"type":"integer"}},"required":["fingerprint","configurations","affectedRecords","uniqueAddresses","reusedAddresses","requiredLookups","unitPriceMicrousd","estimatedCostMicrousd","exclusions"],"type":"object"}]},"GeocodingPreviewInput":{"properties":{"mode":{"default":"gaps","description":"gaps preserves existing address-level coordinates; refresh also refreshes previous Geocodio results, preserving source coordinates.","enum":["gaps","refresh"],"type":"string"},"rerunOf":{"description":"Historical parent job. Reruns create a new job; the parent remains unchanged.","format":"uuid","type":"string"},"scope":{"$ref":"#/components/schemas/GeocodingScope"}},"required":["scope"],"type":"object"},"GeocodingScope":{"properties":{"city":{"description":"Optional recorded address label, not a city polygon.","type":"string"},"postalCode":{"description":"Optional US ZIP or ZIP+4; normalized to five digits.","type":"string"},"state":{"description":"US state name or code; normalized to the two-letter code.","type":"string"}},"required":["state"],"type":"object"},"LocationFilter":{"oneOf":[{"additionalProperties":false,"properties":{"latitude":{"maximum":90,"minimum":-90,"type":"number"},"longitude":{"maximum":180,"minimum":-180,"type":"number"},"radiusMeters":{"exclusiveMinimum":0,"type":"number"},"type":{"const":"point"}},"required":["type","latitude","longitude","radiusMeters"],"type":"object"},{"additionalProperties":false,"properties":{"code":{"description":"Two-letter US state code or five-digit ZIP matching kind. Normalized to uppercase. An active boundary must exist.","type":"string"},"kind":{"enum":["state","zip"],"type":"string"},"radiusMeters":{"default":0,"description":"Distance beyond the area boundary, in meters.","minimum":0,"type":"number"},"type":{"const":"area"}},"required":["type","kind","code"],"type":"object"}]},"LocationMatch":{"description":"Only available when location is supplied. ZIP area matches are possible, not confirmed venue locations. State coverage is broad. Missing coordinates/boundaries stay unresolved.","enum":["point_match","possible_area_match","state_coverage","no_match","unresolved"],"type":"string"},"LocationQueryMetadata":{"properties":{"boundaryDatasets":{"description":"Available active and retained reference versions; not a per-row list of sources used. Preserve Census release/ZCTA vintage attribution.","items":{"properties":{"source":{"type":"string"},"version":{"type":"string"}},"required":["version","source"],"type":"object"},"type":"array"},"filter":{"$ref":"#/components/schemas/LocationFilter"},"pointCoordinates":{"description":"Current responses use source for full stored precision of disclosed coordinates. rounded_to_two_decimal_places remains readable in historical saved metadata. Source quality is described separately.","enum":["source","rounded_to_two_decimal_places"],"type":"string"}},"required":["filter","boundaryDatasets","pointCoordinates"],"type":"object"},"OverseerEvent":{"additionalProperties":false,"properties":{"actorId":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"details":{"description":"Bounded audit summary, state, scheduling information or linked records. Excludes checkpoints, credentials and lease authority. Organization links in details.links include a display label resolved from the current camp name, including historical events. Unnamed or unavailable camps receive an identifying fallback containing the preserved camp ID. Labels do not change stored audit records or action receipts. Completed assistant messages use kind=agent_output with details.text, source (coordinator or subagent), phase (commentary or final_answer), optional ordinal agentLabel, and truncated. Text preserves line breaks after credential redaction and byte bounds. Coordinator final control documents, reasoning, tool payloads and native identities are excluded. These observations do not replace verified progress or directive state; existing history pagination applies. One-off requests use user_message with requestId and text; message_delivered and message_cancelled acknowledge that requestId. A delivery acknowledgment does not establish requested work completion. Global pause transitions use kind=pause_changed with details.paused and details.pauseVersion. They preserve the saved instruction revision.","properties":{"agentLabel":{"description":"Optional ordinal label scoped to an execution; no native identifier.","pattern":"^Subagent [1-9][0-9]*$","type":"string"},"links":{"items":{"properties":{"id":{"type":"string"},"kind":{"type":"string"},"label":{"description":"Current camp name or identifying fallback; present for organization links.","type":"string"}},"type":"object"},"type":"array"},"phase":{"description":"Coordinator events contain commentary only.","enum":["commentary","final_answer"]},"source":{"enum":["coordinator","subagent"]},"text":{"description":"Staff request text for user_message, or credential-redacted assistant text for agent_output. Assistant text preserves whitespace; empty only for an explicit truncation marker.","type":"string"},"truncated":{"description":"The recorded message omits output due to an observation bound.","type":"boolean"},"requestId":{"type":"string","format":"uuid","description":"One-off request identity on user_message, message_delivered and message_cancelled events."},"paused":{"type":"boolean","description":"New desired pause state on pause_changed events."},"pauseVersion":{"type":"integer","minimum":0,"description":"Version of the pause_changed control transition."}},"type":"object"},"directive":{"description":"Actual saved text from this event revision. Present only for directive_saved, including an empty string for idle.","type":"string"},"id":{"minimum":1,"type":"integer"},"kind":{"type":"string"},"revision":{"minimum":0,"type":"integer"}},"required":["id","revision","actorId","kind","details","createdAt"],"type":"object"},"OverseerEvidenceCapture":{"properties":{"capturedAt":{"format":"date-time","type":"string"},"deviceScale":{"const":1},"documentHeight":{"type":"integer"},"documentWidth":{"type":"integer"},"finalUrl":{"type":"string"},"height":{"type":"integer"},"id":{"format":"uuid","type":"string"},"imageDeletedAt":{"description":"When image bytes were removed. Source metadata and update history remain available.","format":"date-time","type":"string"},"pdfPage":{"type":"integer"},"pdfPageCount":{"type":"integer"},"rendererVersion":{"type":"string"},"scrollY":{"type":"integer"},"sha256":{"type":"string"},"sourceKind":{"enum":["webpage","pdf"]},"sourceSha256":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"viewportHeight":{"type":"integer"},"viewportWidth":{"type":"integer"},"warnings":{"description":"Known rendering limitations that reviewers must see next to the original screenshot. Missing source images or fallback fonts can affect interpretation.","items":{"enum":["visible_images_unavailable","fonts_unavailable"],"type":"string"},"type":"array"},"width":{"type":"integer"}},"required":["id","url","finalUrl","capturedAt","sha256","width","height","viewportWidth","viewportHeight","sourceKind","rendererVersion","scrollY","documentWidth","documentHeight","deviceScale"],"type":"object"},"OverseerEvidenceRectangle":{"properties":{"height":{"minimum":1,"type":"integer"},"width":{"minimum":1,"type":"integer"},"x":{"minimum":0,"type":"integer"},"y":{"minimum":0,"type":"integer"}},"required":["x","y","width","height"],"type":"object"},"OverseerLinkedJob":{"additionalProperties":false,"properties":{"campId":{"format":"uuid","type":["string","null"]},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"kind":{"enum":["crawler_job","scraper_job"],"type":"string"},"label":{"type":"string"},"linkedAt":{"format":"date-time","type":"string"},"revision":{"description":"First durable link revision.","minimum":1,"type":"integer"},"status":{"description":"Current status from the actual job queue.","type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"required":["kind","id","revision","label","status","campId","createdAt","updatedAt","linkedAt"],"type":"object"},"OverseerRejectedReviewDecision":{"description":"A durable rejection receipt for exactly this normalized request body and UUID. It is returned only after the rejection has committed. It does not count as a reviewer decision or change canonical records.","properties":{"data":{"type":"null"},"decisionOutcome":{"const":"rejected"},"error":{"const":true},"message":{"type":"string"},"requestId":{"format":"uuid","type":"string"},"success":{"const":false}},"required":["success","error","data","message","requestId","decisionOutcome"],"type":"object"},"OverseerReview":{"properties":{"activityId":{"format":"uuid","type":"string"},"actorId":{"format":"uuid","type":"string"},"appliedResult":{"type":["object","null"],"description":"Immutable application receipt with actual record values, changed fields, and contribution batch identity."},"captures":{"items":{"$ref":"#/components/schemas/OverseerEvidenceCapture"},"type":"array"},"cleared":{"items":{"type":"string"},"type":"array"},"createdAt":{"format":"date-time","type":"string"},"entityId":{"format":"uuid","type":"string"},"evidence":{"items":{"$ref":"#/components/schemas/OverseerReviewEvidence"},"type":"array"},"expected":{"type":"object"},"media":{"$ref":"#/components/schemas/OverseerMediaContribution","description":"Submitted media contribution; the applied result records its actual effect."},"expectedMedia":{"$ref":"#/components/schemas/OverseerMediaProjection","description":"The entity's media when the proposal was made. Omitted when the proposal changes no media."},"mediaInspections":{"type":"array","items":{"$ref":"#/components/schemas/OverseerMediaInspection"},"description":"Omitted when no source image was inspected."},"gapId":{"type":"string","description":"The scraper gap this update addresses; retained in its contribution origin."},"feedback":{"items":{"$ref":"#/components/schemas/OverseerReviewFeedback"},"type":"array"},"feedbackId":{"description":"Latest correction feedback ID for this version. A corrective submission must match the observed feedback identity.","minimum":0,"type":"integer"},"fields":{"type":"object"},"id":{"format":"uuid","type":"string"},"kind":{"enum":["organization","activity","session"]},"label":{"type":"string"},"operation":{"enum":["create","update"]},"organizationId":{"format":"uuid","type":"string"},"originActionId":{"type":"string"},"originRevision":{"type":"integer"},"proposalCreatedAt":{"description":"Creation time of this immutable update version; createdAt is the identity creation time.","format":"date-time","type":"string"},"removeRelevantUrls":{"items":{"type":"string"},"type":"array"},"status":{"enum":["applied","not_applied","revalidation_requested","reverting","reverted","revert_failed"]},"updatedAt":{"format":"date-time","type":"string"},"version":{"minimum":1,"type":"integer"},"auditStatus":{"enum":["unreviewed","reviewed","changes_requested"]},"batchId":{"type":"string","format":"uuid"},"appliedAt":{"type":"string","format":"date-time"},"suppressed":{"type":"boolean"},"revalidationReason":{"type":"string"},"latestVersion":{"type":"integer","minimum":1}},"required":["id","version","kind","organizationId","operation","status","label","originRevision","originActionId","actorId","fields","cleared","removeRelevantUrls","expected","evidence","captures","feedback","createdAt","updatedAt","proposalCreatedAt","auditStatus","suppressed","latestVersion"],"type":"object"},"OverseerMediaSource":{"type":"object","additionalProperties":false,"required":["kind"],"description":"Where a media contribution came from.","properties":{"kind":{"type":"string","enum":["trident","manual","legacy","upload"]},"website":{"type":"string","description":"The website a Trident or manual contribution was read from."},"record_id":{"type":"string","description":"The source record a legacy or Trident contribution belongs to."}}},"OverseerMediaItem":{"type":"object","additionalProperties":false,"required":["url","label","kind","placement"],"description":"One image a contribution adds.","properties":{"url":{"type":"string","description":"Inspected source URL, or final immutable R2 URL from a verified stock import receipt."},"label":{"type":"string"},"kind":{"type":"string"},"placement":{"type":"string","enum":["gallery","logo"],"description":"Where the image is shown: the organization or activity gallery, or the organization logo."},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"source_page_url":{"type":"string"},"observed_at":{"type":"string","format":"date-time"},"stock":{"$ref":"#/components/schemas/OverseerStockImage"}}},"OverseerMediaRemoval":{"type":"object","additionalProperties":false,"required":["media_id","contribution_ids"],"description":"A media member to remove, with the contributions observed for it.","properties":{"media_id":{"type":"string"},"contribution_ids":{"type":"array","items":{"type":"string"}},"baseline":{"type":"boolean","description":"Present and true when the member came from the baseline rather than a contribution."}}},"OverseerMediaContribution":{"type":"object","additionalProperties":false,"required":["mode","source","status","items"],"description":"Typed media changes a proposal makes.","properties":{"mode":{"type":"string","enum":["snapshot","delta"]},"source":{"$ref":"#/components/schemas/OverseerMediaSource"},"status":{"type":"string","enum":["complete","incomplete"]},"items":{"type":"array","items":{"$ref":"#/components/schemas/OverseerMediaItem"}},"remove":{"type":"array","items":{"$ref":"#/components/schemas/OverseerMediaRemoval"},"description":"Omitted when nothing is removed."},"cover_id":{"type":"string","description":"The member to use as the cover. Empty resets automatic selection; omitted leaves it unchanged."},"logo_id":{"type":"string","description":"The member to use as the logo. Empty resets automatic selection; omitted leaves it unchanged."}}},"OverseerMediaResource":{"type":"object","additionalProperties":false,"required":["id"],"properties":{"id":{"type":"string"},"remote_url":{"type":"string"},"uploaded_asset_id":{"type":"string"},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"stock":{"$ref":"#/components/schemas/OverseerStockImage"}}},"OverseerMediaProvenance":{"type":"object","additionalProperties":false,"required":["source"],"properties":{"contribution_id":{"type":"string"},"source":{"$ref":"#/components/schemas/OverseerMediaSource"},"source_page_url":{"type":"string"},"observed_at":{"type":"string","format":"date-time"},"baseline":{"type":"boolean"}}},"OverseerMediaMember":{"type":"object","additionalProperties":false,"required":["resource","placement","position","label","kind","provenance"],"properties":{"resource":{"$ref":"#/components/schemas/OverseerMediaResource"},"placement":{"type":"string","enum":["gallery","logo"],"description":"Where the image is shown: the organization or activity gallery, or the organization logo."},"position":{"type":"integer","minimum":0},"label":{"type":"string"},"kind":{"type":"string"},"provenance":{"type":"array","items":{"$ref":"#/components/schemas/OverseerMediaProvenance"}}}},"OverseerMediaProjection":{"type":"object","additionalProperties":false,"required":["members","cover_id","logo_id","cover_explicit","logo_explicit"],"description":"The media an entity shows: its members and the cover and logo chosen among them.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/OverseerMediaMember"}},"cover_id":{"type":"string"},"logo_id":{"type":"string"},"cover_explicit":{"type":"boolean"},"logo_explicit":{"type":"boolean"}}},"OverseerMediaInspection":{"type":"object","additionalProperties":false,"required":["itemIndex","actionId","candidateId"],"description":"The source-image inspection or stock import receipt that justified adding one media item.","properties":{"itemIndex":{"type":"integer","minimum":0,"description":"Index into media.items."},"actionId":{"type":"string"},"candidateId":{"type":"string"},"mediaId":{"type":"string"}}},"OverseerReviewDecisionInput":{"additionalProperties":false,"properties":{"action":{"enum":["mark_reviewed","request_changes","revert"]},"expectedVersion":{"minimum":1,"type":"integer"},"feedback":{"description":"Required nonempty text for request_changes, at most 8000 UTF-8 bytes. Optional reason for revert.","type":"string"},"requestId":{"format":"uuid","type":"string"}},"required":["expectedVersion","requestId","action"],"type":"object"},"OverseerReviewDetail":{"properties":{"current":{"type":"object"},"currentMissing":{"description":"The current canonical record is unavailable; retained update history and evidence remain readable.","type":"boolean"},"form":{"type":"object"},"proposed":{"type":"object","description":"Actual immutable applied record for applied versions; submitted values for versions that never applied."},"related":{"properties":{"activity":{"description":"Existing parent activity, or an id/missing marker if unavailable.","type":"object"},"hasMoreReviews":{"type":"boolean"},"organization":{"description":"Existing parent organization, or an id/missing marker if unavailable.","type":"object"},"reviews":{"items":{"$ref":"#/components/schemas/OverseerReviewSummary"},"type":"array"}},"required":["organization","reviews","hasMoreReviews"],"type":"object"},"review":{"$ref":"#/components/schemas/OverseerReview"}},"required":["review","form","current","proposed","currentMissing","related"],"type":"object"},"OverseerReviewEvidence":{"properties":{"field":{"type":"string"},"quote":{"type":"string"},"screenshots":{"items":{"properties":{"captureId":{"format":"uuid","type":"string"},"rectangle":{"$ref":"#/components/schemas/OverseerEvidenceRectangle"}},"required":["captureId","rectangle"],"type":"object"},"type":"array"},"url":{"format":"uri","type":"string"},"valuePointer":{"description":"JSON pointer to the normalized proposed value: /fields/name, /fields/relevant_urls/0, /cleared/0, /removeRelevantUrls/0, /organizationId, /activityId or /parentReviewId.","type":"string"}},"required":["field","valuePointer","url","quote","screenshots"],"type":"object"},"OverseerReviewFeedback":{"properties":{"action":{"type":"string","description":"Current review action; historical approve, deny, and retry decisions retain their original audit labels."},"actorId":{"format":"uuid","type":"string"},"createdAt":{"format":"date-time","type":"string"},"feedback":{"type":"string"},"id":{"type":"integer"},"requestId":{"description":"The caller-generated decision request ID; use it to reconcile an uncertain browser response without resubmitting.","format":"uuid","type":"string"},"version":{"type":"integer"}},"required":["id","version","actorId","action","feedback","createdAt","requestId"],"type":"object"},"OverseerReviewGroup":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid"},"label":{"type":"string"},"updateCount":{"type":"integer","minimum":0},"counts":{"$ref":"#/components/schemas/OverseerReviewKindCounts"},"unreviewedCount":{"type":"integer","minimum":0},"changesRequestedCount":{"type":"integer","minimum":0},"newestAt":{"type":"string","format":"date-time"}},"required":["organizationId","label","updateCount","counts","unreviewedCount","changesRequestedCount","newestAt"]},"OverseerReviewGroupsPage":{"type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/components/schemas/OverseerReviewGroup"}},"nextAfterId":{"type":"string"},"hasMore":{"type":"boolean"}},"required":["groups","hasMore"]},"OverseerReviewKindCounts":{"properties":{"activity":{"description":"Number of activity proposals.","minimum":0,"type":"integer"},"organization":{"description":"Number of organization proposals.","minimum":0,"type":"integer"},"session":{"description":"Number of session proposals.","minimum":0,"type":"integer"}},"required":["organization","activity","session"],"type":"object"},"OverseerReviewPage":{"properties":{"counts":{"type":"object","properties":{"applied":{"type":"integer","minimum":0},"not_applied":{"type":"integer","minimum":0},"revalidation_requested":{"type":"integer","minimum":0},"reverting":{"type":"integer","minimum":0},"reverted":{"type":"integer","minimum":0},"revert_failed":{"type":"integer","minimum":0}},"description":"Counts by application status across the entire matching cohort before pagination when entityKind/entityId or retainedOnly=true is supplied; otherwise global version history counts."},"hasMore":{"type":"boolean"},"nextAfterId":{"type":"string"},"reviews":{"items":{"$ref":"#/components/schemas/OverseerReview"},"type":"array"}},"required":["reviews","hasMore","counts"],"type":"object"},"OverseerSlackDelivery":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"deliveredAt":{"format":"date-time","type":["string","null"]},"errorSummary":{"description":"Fixed safe delivery summary; never raw provider or saved error text.","type":["string","null"]},"id":{"minimum":1,"type":"integer"},"kind":{"type":"string"},"revision":{"minimum":1,"type":"integer"},"state":{"enum":["pending","delivering","delivered","failed","cancelled"],"type":"string"}},"required":["id","revision","kind","state","createdAt","deliveredAt","errorSummary"],"type":"object"},"OverseerSnapshot":{"additionalProperties":false,"properties":{"actorId":{"description":"User who last saved the current directive or cleared its memory, or empty before the first save.","type":"string"},"createdAt":{"format":"date-time","type":"string"},"directive":{"type":"string","description":"Compatibility projection containing only the enabled standing instruction text. Use directives when editing."},"executionActive":{"description":"True only when the current revision is running and its worker lease has not expired at response time. A saved but unclaimed directive, absent/expired lease, and execution belonging to a superseded revision return false. Does not establish process health or worker configuration. Always false while paused, including while a revoked native process is finishing cleanup.","type":"boolean"},"latestSlackDelivery":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OverseerSlackDelivery"}]},"leaseExpiresAt":{"description":"Expiry of the current revision worker lease, or null if not claimed. May be in the past; executionActive is then false. Contains no authority token.","format":"date-time","type":["string","null"]},"nextReportAt":{"format":"date-time","type":["string","null"]},"nextWakeAt":{"format":"date-time","type":["string","null"]},"reportCadenceSeconds":{"description":"Worker-interpreted report cadence. Zero disables scheduled reports.","minimum":0,"type":"integer"},"revision":{"minimum":0,"type":"integer"},"state":{"enum":["idle","running","waiting","needs_rewording","satisfied","blocked"],"type":"string"},"subagentCount":{"description":"Last-reported pending or running direct subagents in the current execution. Reports can lag actual activity and exclude nested children. Null while execution is active without valid telemetry; zero when executionActive is false. This is not an instantaneous total or cumulative spawned count.","minimum":0,"type":["integer","null"]},"subagentObservedAt":{"description":"Time the worker recorded the latest valid direct-subagent aggregate. Null when its count is unavailable or executionActive is false. A fresh timestamp does not establish that every child reported a new state.","format":"date-time","type":["string","null"]},"summary":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"directives":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/OverseerDirective"}},"disabledTools":{"type":"array","uniqueItems":true,"items":{"type":"string"},"description":"Disabled names from availableTools. Mandatory history, review reconciliation and lifecycle tools cannot be disabled."},"availableTools":{"type":"array","items":{"$ref":"#/components/schemas/OverseerToolOption"}},"pendingMessages":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/OverseerMessage"},"description":"Undelivered one-off requests for the current revision in submission order. A message being processed remains queued until its turn finishes successfully."},"paused":{"type":"boolean","description":"Global operator pause, independent of instruction revision and underlying work state. Prevents new agent turns and revokes current turn authority without clearing memory, settings or queued requests."},"pauseVersion":{"type":"integer","minimum":0,"description":"Monotonic version for explicit pause/resume changes. Compare with expectedPauseVersion; unchanged desired state with matching versions is a no-op."}},"required":["revision","directive","state","actorId","summary","nextWakeAt","reportCadenceSeconds","nextReportAt","createdAt","updatedAt","executionActive","leaseExpiresAt","latestSlackDelivery","subagentCount","subagentObservedAt","directives","disabledTools","availableTools","pendingMessages","paused","pauseVersion"],"type":"object"},"SessionPrice":{"additionalProperties":false,"description":"One ordered enrollment option with nullable tuition facts, an optional source-grounded description, and optional before- and after-care quotes. At least one tuition fact or care quote must be known; a description alone is invalid. A care-only option does not establish free or known tuition. No currency, basis, or default description is inferred.","not":{"properties":{"price":{"type":"null"},"basis":{"type":"null"},"currency":{"type":"null"},"before_care_pricing":{"type":"null"},"after_care_pricing":{"type":"null"}}},"properties":{"price":{"description":"Stated amount in major currency units. Zero means explicitly free; null means unknown.","minimum":0,"multipleOf":0.01,"type":["number","null"]},"basis":{"description":"Stated rate basis; session covers the entire enrollment. Null means unknown.","enum":["hour","day","week","month","session",null],"type":["string","null"]},"currency":{"description":"Stated three-letter currency code. Null means unknown.","maxLength":3,"minLength":3,"pattern":"^[A-Za-z]{3}$","type":["string","null"]},"description":{"description":"Optional source-grounded distinction such as Members or Non-members, including for a single option. Surrounding whitespace is trimmed; null or blank text is absent and omitted from responses.","type":["string","null"]},"before_care_pricing":{"$ref":"#/components/schemas/CarePricing"},"after_care_pricing":{"$ref":"#/components/schemas/CarePricing"}},"required":["price","basis","currency"],"type":"object"},"SessionScheduleConfiguration":{"additionalProperties":false,"description":"One attendance group sharing session and care hours within an enrollment. Exactly one of explicit dates or a bounded weekly date_rule is required. Effective attendance dates must not overlap another configuration. Aggregate weekly-rule expansion is bounded by safety policy (currently 10,000 effective dates per collection); explicit-date arrays do not consume the limit, and excess is rejected without truncation. Preserve the canonical rule rather than replacing it with expanded dates. Care prices can vary between configurations.","oneOf":[{"not":{"required":["date_rule"]},"required":["dates"]},{"not":{"required":["dates"]},"required":["date_rule"]}],"properties":{"after_care_available":{"description":"False explicitly rules out after care; null means unknown. False cannot carry a care clock or quote.","type":["boolean","null"]},"after_care_end_time":{"description":"Local 24-hour clock in the session time zone; null means unknown.","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","type":["string","null"]},"after_care_pricing":{"$ref":"#/components/schemas/CarePricing"},"before_care_available":{"description":"False explicitly rules out before care; null means unknown. False cannot carry a care clock or quote.","type":["boolean","null"]},"before_care_pricing":{"$ref":"#/components/schemas/CarePricing"},"before_care_start_time":{"description":"Local 24-hour clock in the session time zone; null means unknown.","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","type":["string","null"]},"date_rule":{"$ref":"#/components/schemas/SessionScheduleDateRule"},"dates":{"description":"Explicit attendance dates, possibly nonconsecutive; never inferred from a date envelope.","items":{"description":"An explicitly stated attendance date, YYYY-MM-DD.","format":"date","type":"string"},"minItems":1,"type":"array","uniqueItems":true},"end_time":{"description":"Local 24-hour clock in the session time zone; null means unknown.","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","type":["string","null"]},"start_time":{"description":"Local 24-hour clock in the session time zone; null means unknown.","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","type":["string","null"]}},"type":"object"},"SessionScheduleDateRule":{"additionalProperties":false,"description":"Source-supported weekly attendance within inclusive local calendar bounds. The inclusive bounds differ by at most 3660 days and at least one effective attendance date must remain. Bounds alone never imply weekdays or holiday closures.","properties":{"days_of_week":{"description":"Unique explicitly stated weekdays, normalized in Monday-to-Sunday order.","items":{"enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],"type":"string"},"minItems":1,"type":"array","uniqueItems":true},"end_date":{"description":"Inclusive last local date of the stated rule, YYYY-MM-DD; must not precede start_date.","format":"date","type":"string"},"excluded_dates":{"description":"Optional unique closure dates. Omitted or null means no exclusions; exclusions cannot remove every effective date.","items":{"description":"A source-stated closure on a selected weekday within the inclusive bounds, YYYY-MM-DD.","format":"date","type":"string"},"type":["array","null"],"uniqueItems":true},"start_date":{"description":"Inclusive first local date of the stated rule, YYYY-MM-DD.","format":"date","type":"string"}},"required":["start_date","end_date","days_of_week"],"type":"object"},"BookingError":{"type":"object","required":["error","message"],"properties":{"error":{"const":true},"message":{"type":"string","description":"A sentence you can show the parent as is."},"data":{"type":"null"}}},"BookingMoney":{"type":"object","required":["amountCents","currency"],"properties":{"amountCents":{"type":"integer","description":"Amount in the smallest currency unit, such as cents."},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"ISO 4217 currency code."}},"example":{"amountCents":45000,"currency":"USD"}},"BookingStatus":{"type":"string","enum":["authorizing","prepared","submitting","submit_uncertain","accepted","running","awaiting_decision","confirmed","waitlisted","failed","cancelled","uncertain"],"description":"The step the booking is at, for support and diagnostics. Apps decide what to show from `phase`; each status belongs to exactly one phase, and a new status may be added to an existing phase without notice.","x-open-enum":true},"BookingPaymentStatus":{"type":"string","enum":["none","hold_pending","held","captured","released","failed"],"description":"The state of the hold on the parent’s card. `hold_pending` means a hold attempt’s outcome is unknown; it’s retried with the same idempotency key."},"BookingShareableField":{"type":"string","enum":["child.birthDate","child.grade","child.allergies","guardian.phone"],"description":"Optional profile fields the parent can choose to share. The child’s first and last name and the guardian’s name and email are always shared."},"BookingApprovalInput":{"type":"object","additionalProperties":false,"required":["idempotencyKey","childProfileId","childProfileVersion","sessionId","maxSpend","allowWaitlist","autoAcceptDecisions","shareFields","answers","approveBooking"],"properties":{"idempotencyKey":{"type":"string","format":"uuid","description":"Generate one per approval form. Resending the identical body returns the same booking with `200`; reusing the key with a different body returns `409`."},"childProfileId":{"type":"string","format":"uuid"},"childProfileVersion":{"type":"integer","minimum":1,"description":"The profile version the parent reviewed. If the profile has changed since, the request returns `409`."},"sessionId":{"type":"string","format":"uuid","description":"The catalog session to book."},"maxSpend":{"$ref":"#/components/schemas/BookingMoney","description":"The spending limit, including fees and tax, in the session’s currency and at most 2,500,000 cents. The hold on the parent’s card is for exactly this amount."},"allowWaitlist":{"type":"boolean","description":"Accept a waitlist place if the session is full."},"autoAcceptDecisions":{"type":"boolean","description":"Let School’s Out answer routine camp questions and accept session changes within the spending limit. It never raises spending above the limit, signs a waiver, or creates a camp account."},"shareFields":{"type":"array","items":{"$ref":"#/components/schemas/BookingShareableField"},"uniqueItems":true},"answers":{"type":"array","maxItems":50,"items":{"type":"object","additionalProperties":false,"required":["key","label","value"],"properties":{"key":{"type":"string","maxLength":100},"label":{"type":"string","maxLength":500},"value":{"type":["string","boolean","number"]}}}},"approveBooking":{"const":true,"description":"The parent’s explicit approval. Any other value returns `400`."}},"example":{"idempotencyKey":"0b7c3f52-9a41-4e2d-8f6a-3c1d5e7b9a20","childProfileId":"1f8a3c5e-7b2d-4e9f-a6c1-4d0b8e2f7a93","childProfileVersion":4,"sessionId":"c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48","maxSpend":{"amountCents":45000,"currency":"USD"},"allowWaitlist":true,"autoAcceptDecisions":false,"shareFields":["child.birthDate"],"answers":[{"key":"photo_consent","label":"Photo consent","value":false}],"approveBooking":true}},"BookingDecisionOption":{"type":"object","required":["optionId","label","total"],"properties":{"optionId":{"type":"string"},"label":{"type":"string"},"total":{"oneOf":[{"$ref":"#/components/schemas/BookingMoney"},{"type":"null"}],"description":"The camp’s total if the parent chooses this option."}}},"BookingPendingDecision":{"type":"object","required":["decisionId","code","message","options","proposedOptionId","expiresAt","screenshot"],"properties":{"decisionId":{"type":"string","format":"uuid"},"code":{"type":"string","enum":["unknown_question","choose_option","session_changed","waiver_signature","provider_account_required","unverified_step","answer_required"],"x-open-enum":true},"message":{"type":"string"},"options":{"type":"array","items":{"$ref":"#/components/schemas/BookingDecisionOption"}},"proposedOptionId":{"type":["string","null"]},"expiresAt":{"type":"string","format":"date-time","description":"When the camp’s checkout hold ends. After this, the booking fails with `decision_expired`."},"screenshot":{"description":"The camp’s page as Hallpass last saw it, for an `unverified_step` decision; null otherwise.","oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["mediaType","data","width","height","capturedAt"],"properties":{"mediaType":{"type":"string","enum":["image/jpeg","image/png"]},"data":{"type":"string","description":"Base64 of the image."},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"capturedAt":{"type":"string","format":"date-time"}}}]}}},"BookingDecisionRecord":{"type":"object","required":["decisionId","code","outcome","optionId","decidedBy","decidedAt"],"properties":{"decisionId":{"type":"string","format":"uuid"},"code":{"type":"string"},"outcome":{"type":"string","enum":["accepted","declined","expired"],"x-open-enum":true},"optionId":{"type":["string","null"]},"decidedBy":{"type":["string","null"],"enum":["parent","auto",null]},"decidedAt":{"type":"string","format":"date-time","description":"When the question was answered."}}},"BookingReceipt":{"type":"object","required":["providerReference","providerStatus","amount","confirmedAt"],"properties":{"providerReference":{"type":"string","description":"The camp’s confirmation or order number."},"providerStatus":{"type":"string","enum":["enrolled","waitlisted"]},"amount":{"oneOf":[{"$ref":"#/components/schemas/BookingMoney"},{"type":"null"}],"description":"What the parent was charged. Present only when there was a charge."},"confirmedAt":{"type":"string","format":"date-time","description":"When the camp confirmed the booking."}}},"BookingFailure":{"type":"object","required":["code","message","retryable"],"properties":{"code":{"type":"string","examples":["payment_declined","payment_method_required","booking_rejected","sold_out","price_above_approval","decision_expired"]},"message":{"type":"string"},"retryable":{"type":"boolean","description":"Whether a new, re-approved booking might succeed."}}},"BookingPhase":{"type":"string","enum":["in_progress","needs_parent","booked","waitlisted","not_booked","checking"],"description":"What the booking means to the parent, and which payload it carries. `in_progress`: School’s Out is booking it. `needs_parent`: the camp asked a question only the parent can answer; `decision` carries it. `booked`: the camp enrolled the child; `receipt` carries the confirmation. `waitlisted`: the child holds a waitlist place; `receipt` carries it. `not_booked`: the booking ended without a place; `failure` explains why, or is `null` when the parent cancelled. `checking`: the outcome isn’t known yet; `checkingWith` says whether School’s Out is resolving the card hold or confirming with the camp. Never show `checking` as booked or failed. Adding a phase is a breaking change."},"FamilyBookingCommon":{"type":"object","description":"The fields every booking carries, whatever its phase.","required":["id","phase","status","paymentStatus","childProfileId","organization","session","approval","progressStage","hold","decisions","pollAfterMs","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"phase":{"$ref":"#/components/schemas/BookingPhase"},"status":{"$ref":"#/components/schemas/BookingStatus"},"paymentStatus":{"$ref":"#/components/schemas/BookingPaymentStatus"},"childProfileId":{"type":["string","null"],"format":"uuid","description":"`null` after the profile is deleted. The booking itself remains."},"organization":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"session":{"type":"object","required":["id","name","startDate","endDate"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"startDate":{"type":["string","null"],"format":"date","description":"First day of the session."},"endDate":{"type":["string","null"],"format":"date","description":"Last day of the session."}}},"approval":{"type":"object","required":["approvedAt","maxSpend","allowWaitlist","autoAcceptDecisions","sharedFields"],"properties":{"approvedAt":{"type":"string","format":"date-time","description":"When the parent approved the booking."},"maxSpend":{"$ref":"#/components/schemas/BookingMoney"},"allowWaitlist":{"type":"boolean"},"autoAcceptDecisions":{"type":"boolean"},"sharedFields":{"type":"array","items":{"$ref":"#/components/schemas/BookingShareableField"},"description":"The optional fields the parent chose to share. Always-shared fields aren’t listed."}}},"progressStage":{"type":["string","null"],"enum":["resolving_session","filling_form","reviewing_total","paying","confirming",null],"x-open-enum":true,"description":"The furthest checkout stage Hallpass reported, or `null` before it reports one. New stages may be added."},"hold":{"description":"Why a running run is waiting on something nobody can answer: Pilgrim holding an earlier task for a person's review, Pilgrim's assistance switched off at its Mac, or Hallpass retrying its worker. `null` while the run moves on its own.","oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["code","message","since"],"properties":{"code":{"type":"string","enum":["pilgrim_queue_held","pilgrim_assistance_off","executor_retrying","pilgrim_busy"],"x-open-enum":true},"message":{"type":"string","minLength":1,"maxLength":500,"description":"What the run waits for, written for the requester."},"since":{"type":"string","format":"date-time"}}}]},"decisions":{"type":"array","items":{"$ref":"#/components/schemas/BookingDecisionRecord"}},"pollAfterMs":{"type":["integer","null"],"description":"How long to wait before reading the booking again. `null` once nothing will change without the parent."},"createdAt":{"type":"string","format":"date-time","description":"When the booking was created."},"updatedAt":{"type":"string","format":"date-time","description":"When the booking last changed."}}},"FamilyBookingInProgress":{"description":"School’s Out is placing the card hold or booking with the camp.","allOf":[{"$ref":"#/components/schemas/FamilyBookingCommon"},{"type":"object","required":["phase","status","decision","receipt","failure","checkingWith"],"properties":{"phase":{"type":"string","const":"in_progress"},"status":{"type":"string","enum":["authorizing","prepared","submitting","submit_uncertain","accepted","running"],"x-open-enum":true},"decision":{"type":"null"},"receipt":{"type":"null"},"failure":{"type":"null"},"checkingWith":{"type":"null"}}}]},"FamilyBookingNeedsParent":{"description":"The camp asked a question only the parent can answer. Answer it before `decision.expiresAt`.","allOf":[{"$ref":"#/components/schemas/FamilyBookingCommon"},{"type":"object","required":["phase","status","decision","receipt","failure","checkingWith"],"properties":{"phase":{"type":"string","const":"needs_parent"},"status":{"type":"string","enum":["awaiting_decision"],"x-open-enum":true},"decision":{"$ref":"#/components/schemas/BookingPendingDecision"},"receipt":{"type":"null"},"failure":{"type":"null"},"checkingWith":{"type":"null"}}}]},"FamilyBookingBooked":{"description":"The camp enrolled the child. `receipt` has been checked against the approval. `paymentStatus` may still be `held` while the charge settles.","allOf":[{"$ref":"#/components/schemas/FamilyBookingCommon"},{"type":"object","required":["phase","status","decision","receipt","failure","checkingWith"],"properties":{"phase":{"type":"string","const":"booked"},"status":{"type":"string","enum":["confirmed"],"x-open-enum":true},"decision":{"type":"null"},"receipt":{"$ref":"#/components/schemas/BookingReceipt"},"failure":{"type":"null"},"checkingWith":{"type":"null"}}}]},"FamilyBookingWaitlisted":{"description":"The child holds a waitlist place. `receipt.amount` is present when the camp took a deposit.","allOf":[{"$ref":"#/components/schemas/FamilyBookingCommon"},{"type":"object","required":["phase","status","decision","receipt","failure","checkingWith"],"properties":{"phase":{"type":"string","const":"waitlisted"},"status":{"type":"string","enum":["waitlisted"],"x-open-enum":true},"decision":{"type":"null"},"receipt":{"$ref":"#/components/schemas/BookingReceipt"},"failure":{"type":"null"},"checkingWith":{"type":"null"}}}]},"FamilyBookingNotBooked":{"description":"The booking ended without a place. `failure` is `null` only when the parent cancelled cleanly.","allOf":[{"$ref":"#/components/schemas/FamilyBookingCommon"},{"type":"object","required":["phase","status","decision","receipt","failure","checkingWith"],"properties":{"phase":{"type":"string","const":"not_booked"},"status":{"type":"string","enum":["failed","cancelled"],"x-open-enum":true},"decision":{"type":"null"},"receipt":{"type":"null"},"failure":{"oneOf":[{"$ref":"#/components/schemas/BookingFailure"},{"type":"null"}]},"checkingWith":{"type":"null"}}}]},"FamilyBookingChecking":{"description":"The outcome isn’t known yet. Never show it as booked or failed.","allOf":[{"$ref":"#/components/schemas/FamilyBookingCommon"},{"type":"object","required":["phase","status","decision","receipt","failure","checkingWith"],"properties":{"phase":{"type":"string","const":"checking"},"status":{"type":"string","enum":["uncertain"],"x-open-enum":true},"decision":{"type":"null"},"receipt":{"type":"null"},"failure":{"type":"null"},"checkingWith":{"type":"string","enum":["card","camp"],"description":"`card`: a card hold School’s Out could not resolve. Nothing reached the camp, the parent may cancel, and the child may be booked again. `camp`: School’s Out is confirming the outcome with the camp."}}}]},"FamilyBooking":{"description":"A family booking. `phase` selects the variant and decides which of `decision`, `receipt`, `failure` and `checkingWith` are present.","oneOf":[{"$ref":"#/components/schemas/FamilyBookingInProgress"},{"$ref":"#/components/schemas/FamilyBookingNeedsParent"},{"$ref":"#/components/schemas/FamilyBookingBooked"},{"$ref":"#/components/schemas/FamilyBookingWaitlisted"},{"$ref":"#/components/schemas/FamilyBookingNotBooked"},{"$ref":"#/components/schemas/FamilyBookingChecking"}],"discriminator":{"propertyName":"phase","mapping":{"in_progress":"#/components/schemas/FamilyBookingInProgress","needs_parent":"#/components/schemas/FamilyBookingNeedsParent","booked":"#/components/schemas/FamilyBookingBooked","waitlisted":"#/components/schemas/FamilyBookingWaitlisted","not_booked":"#/components/schemas/FamilyBookingNotBooked","checking":"#/components/schemas/FamilyBookingChecking"}}},"BookingEventKind":{"type":"string","enum":["approval_granted","payment_hold_placed","payment_hold_failed","task_submitted","task_submit_uncertain","task_status_observed","decision_requested","decision_accepted","decision_declined","confirmation_received","payment_captured","payment_capture_failed","payment_released","cancel_requested","reconciled"],"x-open-enum":true,"description":"What happened. New kinds may be added; show `summary` for a kind you don’t recognise."},"BookingActor":{"type":"string","enum":["parent","auto","hallpass","system","staff"],"x-open-enum":true,"description":"Who caused the event. New actors may be added."},"BookingEvent":{"type":"object","required":["kind","status","actor","summary","createdAt"],"properties":{"kind":{"$ref":"#/components/schemas/BookingEventKind"},"status":{"$ref":"#/components/schemas/BookingStatus","description":"The booking’s status after this event."},"actor":{"$ref":"#/components/schemas/BookingActor"},"summary":{"type":"string","maxLength":500},"createdAt":{"type":"string","format":"date-time","description":"When the event was recorded."}}},"FamilyBookingDetail":{"allOf":[{"$ref":"#/components/schemas/FamilyBooking"},{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/BookingEvent"},"description":"The full history, oldest first."}}}]},"BookingPaymentMethod":{"type":"object","required":["brand","last4"],"properties":{"brand":{"type":"string","description":"Can be empty; show “Card” in that case."},"last4":{"type":"string","pattern":"^[0-9]{4}$"}}},"CanonicalProvenanceRow":{"additionalProperties":false,"properties":{"configuration_id":{"format":"uuid","type":["string","null"]},"created_at":{"description":"Recorded bookkeeping timestamp; not a verification or freshness guarantee.","format":"date-time","type":["string","null"]},"external_ids":{"description":"Retained external identifiers when permitted by the field mask."},"field_provenance":{"$ref":"#/components/schemas/CanonicalFieldProvenance"},"id":{"format":"uuid","type":"string"},"merge_jobs":{"description":"Raw retained history, available only to ADMIN user-backed viewers.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"relationship_jobs":{"description":"Raw retained history, available only to ADMIN user-backed viewers.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"source_created_at":{"description":"Recorded bookkeeping timestamp; not a verification or freshness guarantee.","format":"date-time","type":["string","null"]},"source_records":{"description":"Raw retained history, available only to ADMIN user-backed viewers.","items":{"additionalProperties":true,"type":"object"},"type":"array"},"updated_at":{"description":"Recorded bookkeeping timestamp; not a verification or freshness guarantee.","format":"date-time","type":["string","null"]}},"required":["id"],"type":"object"},"CrawlerAcquisitionBudget":{"additionalProperties":false,"properties":{"max_candidate_sites":{"type":["integer","null"]},"max_model_requests":{"type":["integer","null"]},"max_pages":{"type":["integer","null"]},"max_pages_per_site":{"type":["integer","null"]},"max_search_queries":{"type":["integer","null"]}},"required":["max_candidate_sites","max_model_requests","max_pages","max_pages_per_site","max_search_queries"],"type":"object"},"CrawlerAttempt":{"additionalProperties":false,"properties":{"attempt_number":{"type":"integer"},"completion_reason":{"type":["string","null"]},"evaluation_id":{"type":["string","null"]},"finished_at":{"format":"date-time","type":["string","null"]},"heartbeat_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"instance_name":{"type":"string"},"job_id":{"type":"string"},"lease_expires_at":{"format":"date-time","type":"string"},"session_id":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"type":"string","enum":["running","completed","partial","blocked","failed","expired","interrupted","cancelled"]}},"required":["attempt_number","completion_reason","evaluation_id","finished_at","id","job_id","lease_expires_at","session_id","started_at","status"],"type":"object"},"CrawlerComparison":{"additionalProperties":false,"properties":{"added":{"items":{"type":"string"},"type":"array"},"errors":{"items":{"type":"string"},"type":"array"},"output_urls":{"items":{"type":"string"},"type":"array"},"pending":{"items":{"type":"string"},"type":"array"},"removed":{"items":{"type":"string"},"type":"array"},"uncertain":{"items":{"type":"string"},"type":"array"},"unchanged":{"items":{"type":"string"},"type":"array"}},"required":["added","errors","output_urls","pending","removed","uncertain","unchanged"],"type":"object"},"CrawlerConfig":{"additionalProperties":false,"properties":{"id":{"type":"string"},"model":{"type":"string"},"prompt":{"type":"string"},"settings":{"additionalProperties":{},"type":"object"}},"required":["id","model","prompt","settings"],"type":"object"},"CrawlerCounts":{"additionalProperties":false,"properties":{"crawled":{"type":"integer"},"decided":{"type":"integer"},"discovered":{"type":"integer"},"errors":{"type":"integer"},"excluded":{"type":"integer"},"pending":{"type":"integer"},"retained":{"type":"integer"},"uncertain":{"type":"integer"}},"required":["crawled","decided","discovered","errors","excluded","pending","retained","uncertain"],"type":"object"},"CrawlerDetail":{"additionalProperties":false,"properties":{"attempt_count":{"type":"integer"},"attempts":{"items":{"$ref":"#/components/schemas/CrawlerAttempt"},"type":"array"},"attempts_truncated":{"type":"boolean"},"evaluation_count":{"type":"integer"},"evaluations":{"items":{"$ref":"#/components/schemas/CrawlerEvaluation"},"type":"array"},"evaluations_truncated":{"type":"boolean"},"event_count":{"type":"integer"},"events":{"items":{"$ref":"#/components/schemas/CrawlerEvent"},"type":"array"},"events_truncated":{"type":"boolean"},"job":{"$ref":"#/components/schemas/CrawlerJob"},"latest_progress":{"$ref":"#/components/schemas/CrawlerEvent"},"result_count":{"type":"integer"},"results":{"items":{"$ref":"#/components/schemas/CrawlerResult"},"type":"array"}},"required":["attempt_count","attempts","attempts_truncated","evaluation_count","evaluations","evaluations_truncated","event_count","events","events_truncated","job","result_count","results"],"type":"object"},"CrawlerDiscoveryPath":{"additionalProperties":false,"properties":{"providers":{"items":{"type":"string"},"type":"array"},"reason":{"type":"string"},"status":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/CrawlerDiscoveryPathStep"},"type":"array"}},"required":["providers","reason","status","steps"],"type":"object"},"CrawlerDiscoveryPathStep":{"additionalProperties":false,"properties":{"url":{"type":"string"},"via":{"type":"string"}},"required":["url","via"],"type":"object"},"CrawlerEvaluationCounts":{"additionalProperties":false,"properties":{"added":{"type":"integer"},"crawled":{"type":"integer"},"decided":{"type":"integer"},"discovered":{"type":"integer"},"errors":{"type":"integer"},"excluded":{"type":"integer"},"pending":{"type":"integer"},"removed":{"type":"integer"},"retained":{"type":"integer"},"uncertain":{"type":"integer"}},"required":["added","crawled","decided","discovered","errors","excluded","pending","removed","retained","uncertain"],"type":"object"},"CrawlerEvaluationDetail":{"additionalProperties":false,"properties":{"comparison":{"$ref":"#/components/schemas/CrawlerComparison"},"evaluation":{"$ref":"#/components/schemas/CrawlerEvaluation"}},"required":["comparison","evaluation"],"type":"object"},"CrawlerEvaluationResult":{"additionalProperties":false,"properties":{"baseline_included":{"type":"boolean"},"depth":{"type":"integer"},"discovery_path":{"$ref":"#/components/schemas/CrawlerDiscoveryPath"},"excluded":{"type":"boolean"},"fetched_at":{"format":"date-time","type":["string","null"]},"final_url":{"type":"string"},"included":{"type":"boolean"},"no_probability":{"type":["number","null"]},"providers":{"items":{"type":"string"},"type":"array"},"reason":{"type":"string"},"site_assessment":{"$ref":"#/components/schemas/CrawlerSiteAssessment"},"site_preview":{"$ref":"#/components/schemas/CrawlerSiteAssessment"},"status":{"type":"string","enum":["discovered","crawled","blocked","failed","skipped"]},"url":{"type":"string"},"verdict":{"type":["string","null"],"enum":["relevant","irrelevant","uncertain","error",null]},"yes_probability":{"type":["number","null"]}},"required":["baseline_included","depth","excluded","fetched_at","final_url","included","no_probability","providers","reason","status","url","verdict","yes_probability"],"type":"object"},"CrawlerEvaluationResultCounts":{"additionalProperties":false,"properties":{"added":{"type":"integer"},"changed":{"type":"integer"},"errors":{"type":"integer"},"excluded":{"type":"integer"},"included":{"type":"integer"},"pending":{"type":"integer"},"removed":{"type":"integer"},"total":{"type":"integer"},"uncertain":{"type":"integer"}},"required":["added","changed","errors","excluded","included","pending","removed","total","uncertain"],"type":"object"},"CrawlerEvaluationResultsPage":{"type":"object","additionalProperties":false,"description":"One page of a JEV session's results, compared with its baseline.","required":["evaluation","baseline_evaluation_id","counts","results","total","page","pageSize"],"properties":{"evaluation":{"$ref":"#/components/schemas/CrawlerEvaluation"},"baseline_evaluation_id":{"type":["string","null"],"description":"The comparison baseline used; null means the original crawl outputs."},"counts":{"$ref":"#/components/schemas/CrawlerEvaluationResultCounts"},"results":{"type":"array","items":{"$ref":"#/components/schemas/CrawlerEvaluationResult"}},"total":{"type":"integer","minimum":0},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","minimum":1},"preview_counts":{"$ref":"#/components/schemas/CrawlerTridentPreviewCounts"},"preview_attempt_id":{"type":["string","null"]},"preview_revision":{"type":"string"}}},"CrawlerEvent":{"additionalProperties":false,"properties":{"attempt_id":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"details":{"additionalProperties":{},"type":"object"},"id":{"type":"string"},"job_id":{"type":"string"},"kind":{"type":"string"}},"required":["attempt_id","created_at","details","id","job_id","kind"],"type":"object"},"CrawlerJob":{"additionalProperties":false,"properties":{"acquisition_budget":{"$ref":"#/components/schemas/CrawlerAcquisitionBudget"},"activity_filter":{"type":"boolean"},"completion_reason":{"type":["string","null"]},"contract_version":{"type":"integer"},"counts":{"$ref":"#/components/schemas/CrawlerCounts"},"created_at":{"format":"date-time","type":"string"},"finished_at":{"format":"date-time","type":["string","null"]},"id":{"type":"string"},"initial_jev_config":{"$ref":"#/components/schemas/CrawlerConfig"},"initial_jev_config_id":{"type":["string","null"]},"latest_event":{"$ref":"#/components/schemas/CrawlerEvent"},"max_crawl_depth":{"type":["integer","null"]},"max_urls_per_site":{"type":["integer","null"]},"mode":{"type":"string","enum":["search","organization_website"]},"organization":{"$ref":"#/components/schemas/CrawlerOrganizationInput"},"provider_mask":{"type":"integer"},"queue":{"$ref":"#/components/schemas/CrawlerQueueEligibility"},"saved_results":{"$ref":"#/components/schemas/CrawlerSavedResults"},"search_exclude_domains":{"items":{"type":"string"},"type":"array"},"search_include_domains":{"items":{"type":"string"},"type":"array"},"search_term":{"type":"string"},"settings_mask":{"type":"integer"},"site_resolution":{"$ref":"#/components/schemas/CrawlerSiteResolution"},"stage":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","partial","blocked","failed","cancelled"]},"updated_at":{"format":"date-time","type":"string"}},"required":["activity_filter","completion_reason","contract_version","counts","created_at","finished_at","id","initial_jev_config_id","max_crawl_depth","max_urls_per_site","provider_mask","search_exclude_domains","search_include_domains","search_term","settings_mask","stage","status","updated_at"],"type":"object"},"CrawlerOrganizationInput":{"additionalProperties":false,"properties":{"address":{"type":"string"},"description":{"type":"string"},"email":{"type":"string"},"location":{"type":"string"},"name":{"type":"string"},"phone":{"type":"string"},"registration_url":{"type":"string"},"source_url":{"type":"string"},"website_url":{"type":"string"}},"required":["name"],"type":"object"},"CrawlerQueueEligibility":{"additionalProperties":false,"properties":{"active_workers":{"type":"integer"},"available_at":{"format":"date-time","type":"string"},"compatible_workers":{"type":"integer"},"message":{"type":"string"},"ready_workers":{"type":"integer"},"state":{"type":"string"},"workers":{"items":{"$ref":"#/components/schemas/CrawlerQueueWorker"},"type":"array"},"workers_truncated":{"type":"boolean"}},"required":["active_workers","available_at","compatible_workers","message","ready_workers","state","workers","workers_truncated"],"type":"object"},"CrawlerQueueWorker":{"additionalProperties":false,"properties":{"busy":{"type":"boolean"},"missing_provider_mask":{"type":"integer"},"missing_settings_mask":{"type":"integer"},"name":{"type":"string"},"supports_contract":{"type":"boolean"}},"required":["busy","missing_provider_mask","missing_settings_mask","name","supports_contract"],"type":"object"},"CrawlerResult":{"additionalProperties":false,"properties":{"depth":{"type":"integer"},"discovery_path":{"$ref":"#/components/schemas/CrawlerDiscoveryPath"},"excluded":{"type":"boolean"},"fetched_at":{"format":"date-time","type":["string","null"]},"final_url":{"type":"string"},"no_probability":{"type":["number","null"]},"providers":{"items":{"type":"string"},"type":"array"},"reason":{"type":"string"},"site_assessment":{"$ref":"#/components/schemas/CrawlerSiteAssessment"},"status":{"type":"string","enum":["discovered","crawled","blocked","failed","skipped"]},"url":{"type":"string"},"verdict":{"type":["string","null"],"enum":["relevant","irrelevant","uncertain","error",null]},"yes_probability":{"type":["number","null"]}},"required":["depth","excluded","fetched_at","final_url","no_probability","providers","reason","status","url","verdict","yes_probability"],"type":"object"},"CrawlerResultsPage":{"type":"object","additionalProperties":false,"description":"One page of a crawl's saved results, from its latest or chosen attempt.","required":["results","total","attempt","counts","site_resolution","page","pageSize"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/CrawlerResult"}},"total":{"type":"integer","minimum":0},"attempt":{"oneOf":[{"$ref":"#/components/schemas/CrawlerAttempt"},{"type":"null"}]},"counts":{"$ref":"#/components/schemas/CrawlerCounts"},"site_resolution":{"oneOf":[{"$ref":"#/components/schemas/CrawlerSiteResolution"},{"type":"null"}]},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","minimum":1}}},"CrawlerSavedResults":{"additionalProperties":false,"properties":{"attempt_id":{"type":"string"},"attempt_number":{"type":"integer"},"counts":{"$ref":"#/components/schemas/CrawlerCounts"}},"required":["attempt_id","attempt_number","counts"],"type":"object"},"CrawlerSiteAssessment":{"additionalProperties":false,"properties":{"activity_reason":{"type":"string"},"activity_status":{"type":"string","enum":["relevant","irrelevant","unresolved","blocked"]},"decision":{"type":"string","enum":["eligible","rejected","unresolved"]},"discovery":{"items":{"$ref":"#/components/schemas/CrawlerSiteDiscovery"},"type":"array"},"evidence":{"items":{"$ref":"#/components/schemas/CrawlerSiteEvidence"},"type":"array"},"homepage_url":{"type":["string","null"]},"identity_reason":{"type":"string"},"identity_status":{"type":"string","enum":["verified","not_applicable","ambiguous","unresolved","rejected"]},"policy_version":{"type":"integer"},"reason":{"type":"string"},"root_url":{"type":"string"},"site_role":{"type":"string","enum":["first_party","aggregator","directory","social","shared_platform","unknown"]}},"required":["activity_reason","activity_status","decision","discovery","evidence","homepage_url","identity_reason","identity_status","policy_version","reason","root_url","site_role"],"type":"object"},"CrawlerSiteDiscovery":{"additionalProperties":false,"properties":{"provider":{"type":"string"},"query":{"type":"string"},"source_summary":{"type":"string"},"source_url":{"type":"string"},"url":{"type":"string"}},"required":["url"],"type":"object"},"CrawlerSiteEvidence":{"additionalProperties":false,"properties":{"content_sha256":{"type":"string"},"excerpt":{"type":"string"},"fetched_at":{"format":"date-time","type":"string"},"kind":{"type":"string"},"url":{"type":"string"}},"required":["content_sha256","excerpt","fetched_at","kind","url"],"type":"object"},"CrawlerSiteResolution":{"additionalProperties":false,"properties":{"homepage_url":{"type":["string","null"]},"reason":{"type":"string"},"status":{"type":"string"},"usage":{"$ref":"#/components/schemas/CrawlerSiteUsage"}},"required":["homepage_url","reason","status","usage"],"type":"object"},"CrawlerSiteUsage":{"additionalProperties":false,"properties":{"candidate_sites":{"type":"integer"},"cost_usd":{"type":["number","null"]},"model_requests":{"type":"integer"},"page_fetches":{"type":"integer"},"search_queries":{"type":"integer"},"transport_request_limit":{"type":["integer","null"]},"transport_requests":{"type":"integer"}},"required":["candidate_sites","cost_usd","model_requests","page_fetches","search_queries","transport_request_limit","transport_requests"],"type":"object"},"CrawlerTridentPreviewCounts":{"additionalProperties":false,"properties":{"checked":{"type":"integer"},"eligible":{"type":"integer"},"errors":{"type":"integer"},"ineligible":{"type":"integer"},"pending":{"type":"integer"},"total":{"type":"integer"},"uncertain":{"type":"integer"}},"required":["checked","eligible","errors","ineligible","pending","total","uncertain"],"type":"object"},"ScraperArtifact":{"additionalProperties":false,"properties":{"attempt_id":{"type":"string"},"body":{},"created_at":{"format":"date-time","type":"string"},"id":{"type":"integer"},"key":{"type":"string"},"kind":{"type":"string"},"omitted":{"type":"string"},"size_bytes":{"type":"integer"}},"required":["attempt_id","created_at","id","kind","size_bytes"],"type":"object"},"ScraperArtifactSummary":{"additionalProperties":false,"properties":{"attempt_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"integer"},"key":{"type":"string"},"kind":{"type":"string"},"omitted":{"type":"string"},"size_bytes":{"type":"integer"}},"required":["attempt_id","created_at","id","kind","size_bytes"],"type":"object"},"ScraperAttempt":{"additionalProperties":false,"properties":{"error":{"type":"string"},"finished_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"job_id":{"type":"string"},"lease_expires_at":{"format":"date-time","type":"string"},"number":{"type":"integer"},"session_id":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"type":"string","enum":["running","completed","failed","expired","interrupted","paused"]}},"required":["id","job_id","lease_expires_at","number","session_id","started_at","status"],"type":"object"},"ScraperCodexAccount":{"additionalProperties":false,"properties":{"code_expires_at":{"format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"type":"string"},"device_url":{"type":["string","null"]},"email":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":"string"},"last_error":{"type":["string","null"]},"last_used_at":{"format":"date-time","type":["string","null"]},"leased_at":{"format":"date-time","type":["string","null"]},"leased_by":{"oneOf":[{"$ref":"#/components/schemas/ScraperCodexAccountLessee"},{"type":"null"}]},"plan":{"type":["string","null"]},"resets_5h_at":{"format":"date-time","type":["string","null"],"description":"When the five-hour window resets, as last read."},"resets_at":{"format":"date-time","type":["string","null"]},"resets_week_at":{"format":"date-time","type":["string","null"],"description":"When the weekly window resets, as last read."},"status":{"type":"string","enum":["pending_login","awaiting_approval","active","exhausted","login_failed","login_required","removing","removed"]},"updated_at":{"format":"date-time","type":"string"},"usage_ceiling_pct":{"type":["integer","null"],"minimum":1,"maximum":100,"description":"Operator's usage ceiling in percent, or null for none. While used_5h_pct or used_week_pct is at or above it the subscription stays active and logged in but workers do not lease it."},"used_5h_pct":{"type":["number","null"]},"used_week_pct":{"type":["number","null"]},"user_code":{"type":["string","null"]}},"required":["code_expires_at","created_at","created_by","device_url","email","id","label","last_error","last_used_at","leased_at","leased_by","plan","resets_5h_at","resets_at","resets_week_at","status","updated_at","usage_ceiling_pct","used_5h_pct","used_week_pct","user_code"],"type":"object"},"ScraperCodexAccountLessee":{"additionalProperties":false,"properties":{"instance_id":{"type":"string"},"name":{"type":"string"}},"required":["instance_id","name"],"type":"object"},"ScraperCodexAccountRef":{"additionalProperties":false,"properties":{"email":{"type":["string","null"]},"id":{"type":"string"},"label":{"type":"string"}},"required":["email","id","label"],"type":"object"},"ScraperEvent":{"additionalProperties":false,"properties":{"activities":{"type":"integer"},"attempt_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"detail":{"type":"string"},"duration_milliseconds":{"type":"integer"},"exit_code":{"type":"integer"},"id":{"type":"integer"},"message":{"type":"string"},"metrics":{"additionalProperties":{"type":"integer"},"type":"object"},"model":{"type":"string"},"operation":{"type":"string"},"organizations":{"type":"integer"},"pages":{"type":"integer"},"sessions":{"type":"integer"},"stage":{"type":"string"},"state":{"type":"string","enum":["running","succeeded","failed","canceled"]},"target":{"type":"string"},"warnings":{"items":{"type":"string"},"type":"array"}},"required":["attempt_id","created_at","id","stage","state"],"type":"object"},"ScraperBuildStatus":{"additionalProperties":false,"type":"object","properties":{"revision":{"type":"string"},"main_revision":{"oneOf":[{"type":"string","pattern":"^[0-9a-f]{40}$"},{"type":"null"}]},"behind_main":{"oneOf":[{"type":"integer","minimum":0},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["revision","main_revision","behind_main","checked_at"]},"ScraperUpdateRequest":{"additionalProperties":false,"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["update","rollback"]},"status":{"type":"string","enum":["pending","draining","running","succeeded","rolled_back","failed","refused"]},"target_revision":{"oneOf":[{"type":"string","pattern":"^[0-9a-f]{40}$"},{"type":"null"}]},"from_revision":{"oneOf":[{"type":"string","pattern":"^[0-9a-f]{40}$"},{"type":"null"}]},"to_revision":{"oneOf":[{"type":"string","pattern":"^[0-9a-f]{40}$"},{"type":"null"}]},"message":{"oneOf":[{"type":"string","maxLength":300},{"type":"null"}]},"log_tail":{"oneOf":[{"type":"string","maxLength":4096},{"type":"null"}]},"requested_by":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"finished_at":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","action","status","target_revision","from_revision","to_revision","message","log_tail","requested_by","created_at","updated_at","finished_at"]},"ScraperInstance":{"additionalProperties":false,"properties":{"availability":{"type":"string"},"codex_account":{"oneOf":[{"$ref":"#/components/schemas/ScraperCodexAccountRef"},{"type":"null"}]},"created_at":{"format":"date-time","type":"string"},"current_job":{"$ref":"#/components/schemas/ScraperJob"},"id":{"type":"string"},"last_seen_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"provider_pauses":{"items":{"$ref":"#/components/schemas/ScraperProviderPause"},"type":"array"},"session":{"$ref":"#/components/schemas/ScraperSession"},"build":{"$ref":"#/components/schemas/ScraperBuildStatus"},"current_jobs":{"type":"array","items":{"$ref":"#/components/schemas/ScraperJob"}},"update":{"oneOf":[{"$ref":"#/components/schemas/ScraperUpdateRequest"},{"type":"null"}]}},"required":["availability","codex_account","created_at","id","name","build","current_jobs","update"],"type":"object"},"ScraperJob":{"additionalProperties":false,"properties":{"batch_id":{"type":"string"},"contract_version":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"error":{"type":"string"},"id":{"type":"string"},"instance_id":{"type":"string"},"kind":{"type":"string","enum":["onboarding","refresh","adapter_repair"]},"latest_event":{"$ref":"#/components/schemas/ScraperEvent"},"max_attempts":{"type":"integer"},"not_before":{"format":"date-time","type":"string"},"parent_job_id":{"type":"string"},"settings":{"$ref":"#/components/schemas/ScraperScrapeSettings"},"status":{"type":"string","enum":["queued","running","completed","failed","paused"]},"unsupported_reason":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"website":{"type":"string"}},"required":["contract_version","created_at","id","instance_id","kind","max_attempts","not_before","status","updated_at","website"],"type":"object"},"ScraperJobDetail":{"additionalProperties":false,"properties":{"attempts":{"items":{"$ref":"#/components/schemas/ScraperAttempt"},"type":"array"},"batch_ids":{"items":{"type":"string"},"type":"array"},"event_count":{"type":"integer"},"events":{"items":{"$ref":"#/components/schemas/ScraperEvent"},"type":"array"},"events_truncated":{"type":"boolean"},"job":{"$ref":"#/components/schemas/ScraperJob"},"publication":{"$ref":"#/components/schemas/ScraperWebsitePublication"}},"required":["attempts","batch_ids","event_count","events","events_truncated","job"],"type":"object"},"ScraperProviderPause":{"additionalProperties":false,"properties":{"paused_at":{"format":"date-time","type":"string"},"probe_error":{"type":"string"},"probed_at":{"format":"date-time","type":"string"},"probes":{"type":"integer"},"provider":{"type":"string","enum":["typesafe","codex","openai","anthropic","google","geonode"]},"reason":{"type":"string"}},"required":["paused_at","probes","provider","reason"],"type":"object"},"ScraperScrapeSettings":{"additionalProperties":false,"properties":{"approved_external_origin":{"type":"string"},"capture_timeout_ms":{"type":"integer"},"crawl_delay_ms":{"type":"integer"},"dom_quiet_window_ms":{"type":"integer"},"include_subdomains":{"type":"boolean"},"max_corpus_pages":{"type":"integer"},"max_discovery_pages":{"type":"integer"},"max_model_calls":{"type":"integer"},"max_typesafe_requests":{"type":"integer"}},"type":"object"},"ScraperSession":{"additionalProperties":false,"properties":{"build_revision":{"type":"string"},"heartbeat_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"instance_id":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"stopped_at":{"format":"date-time","type":"string"},"supported_versions":{"items":{"type":"integer"},"type":"array"}},"required":["build_revision","heartbeat_at","id","instance_id","started_at","supported_versions"],"type":"object"},"ScraperWebsitePublication":{"additionalProperties":false,"properties":{"batches":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ScraperWebsitePublicationBatchStatus"},"description":"Null before any batch has been staged."},"has_errors":{"type":"boolean"},"needs_review":{"type":"boolean"},"relationships":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ScraperWebsitePublicationRelationshipStatus"},"description":"Null when the website has no staged relationships."},"settled":{"type":"boolean"}},"required":["batches","has_errors","needs_review","relationships","settled"],"type":"object"},"ScraperWebsitePublicationBatchStatus":{"additionalProperties":false,"properties":{"eligible_count":{"type":"integer"},"failed_count":{"type":"integer"},"id":{"type":"string"},"merged_count":{"type":"integer"},"record_count":{"type":"integer"},"result_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Null until the batch's records have been merged."},"status":{"type":"string"},"target_kind":{"type":"string"}},"required":["eligible_count","failed_count","id","merged_count","record_count","result_ids","status","target_kind"],"type":"object"},"ScraperWebsitePublicationRelationshipStatus":{"additionalProperties":false,"properties":{"id":{"type":"string"},"relationship_kind":{"type":"string"},"review_required":{"type":"boolean"},"status":{"type":"string"}},"required":["id","relationship_kind","review_required","status"],"type":"object"},"OverseerDirective":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1,"maxLength":100,"description":"Stable caller-assigned identity, unique in this list; at most 100 UTF-8 bytes."},"text":{"type":"string","minLength":1,"description":"Nonempty instruction. Saved after trimming surrounding whitespace; all item text together is at most 65536 UTF-8 bytes."},"enabled":{"type":"boolean","description":"Only enabled instructions are supplied as current standing instructions to the worker."}},"required":["id","text","enabled"]},"OverseerToolOption":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"}},"required":["name","label","description"]},"OverseerMessage":{"type":"object","additionalProperties":false,"properties":{"requestId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1},"text":{"type":"string"},"actorId":{"type":"string"},"status":{"type":"string","enum":["queued","delivered","cancelled"],"description":"Delivered means supplied to a successfully completed agent turn, not proof that requested work finished."},"createdAt":{"type":"string","format":"date-time"},"deliveredAt":{"type":["string","null"],"format":"date-time"},"cancelledAt":{"type":["string","null"],"format":"date-time"}},"required":["requestId","revision","text","actorId","status","createdAt","deliveredAt","cancelledAt"]},"CanonicalFilter":{"description":"A bounded recursive canonical predicate tree. Every node has exactly one form. Field names, operators, relations and special predicates must be advertised by the current entity table filterCapabilities. Every branch is validated against current tier and preview disclosure before execution. Legacy query parameters combine with this tree using AND. No general negation. Null is unknown, never false, free or unrestricted. Conditions inside one related.where match the same related record; separate related nodes may match different records. Runtime also validates field-specific types, permissions, depth, total node count and encoded byte size. Map, member and summary operations project the selected root through the camp cohort described by their filterKind parameter; global search suggestions remain separate.","oneOf":[{"$ref":"#/components/schemas/CanonicalFilterAll"},{"$ref":"#/components/schemas/CanonicalFilterAny"},{"$ref":"#/components/schemas/CanonicalFilterField"},{"$ref":"#/components/schemas/CanonicalFilterRelated"},{"$ref":"#/components/schemas/CanonicalFilterRadius"},{"$ref":"#/components/schemas/CanonicalFilterPrice"},{"$ref":"#/components/schemas/CanonicalFilterSchedule"}],"examples":[{"related":{"relation":"sessions","match":"any","where":{"all":[{"field":"age_range_years","op":"contains","value":10},{"price":{"maximum":400,"currency":"USD","basis":"week"}}]}}},{"any":[{"field":"overnight","op":"missing"},{"field":"overnight","op":"eq","value":false}]},{"schedule":{"mode":"covers","from":"2027-06-14","to":"2027-06-18","daysOfWeek":["monday","tuesday","wednesday","thursday","friday"],"startTime":"09:00","endTime":"17:00","timeZone":"venueLocal","includeCare":true}}]},"CanonicalFilterAll":{"type":"object","additionalProperties":false,"properties":{"all":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalFilter"},"minItems":1,"maxItems":64}},"required":["all"]},"CanonicalFilterAny":{"type":"object","additionalProperties":false,"properties":{"any":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalFilter"},"minItems":1,"maxItems":64}},"required":["any"]},"CanonicalFilterField":{"type":"object","additionalProperties":false,"properties":{"field":{"type":"string","minLength":1,"description":"Canonical field name from filterCapabilities.fields; age_range_months is a compatibility alias and is not accepted. Filter-only score (numeric, 0 through 100) and score_band (weak, fair, good, strong) read the current entity's persisted list-score source, including in related predicates. They require paid access and are unavailable in previews. Missing scores are null, not zero or an unavailable band; use missing or eq null. score supports numeric comparisons and in; score_band supports eq and in; both support missing and present. Filtering does not add scores to entity records or calculate scores during reads."},"op":{"type":"string","enum":["eq","in","missing","present","empty","lt","lte","gt","gte","containsText","matchesRegion","containsAny","containsAll","contains","overlaps"]},"value":{"description":"Typed JSON value for the selected field and operator. eq supports null (same as missing); JSON fields compare whole structural values. in requires 1–100 non-null scalar values. containsAny/containsAll require 1–100 whole members; categories and text arrays require strings. Non-array JSON never satisfies membership. contains takes one whole age/grade; overlaps takes two inclusive range endpoints with null for an open bound. Number and boolean fields require JSON numbers and booleans; dates use YYYY-MM-DD, timestamps RFC 3339. Text eq/in are exact and case-sensitive; containsText is a literal case-insensitive substring. matchesRegion accepts nonblank text on region only: US state/territory codes and full names are aliases, with case and surrounding ASCII whitespace ignored. Other labels use trimmed case-insensitive equality. This matches recorded labels without verifying country; eq/in retain literal semantics."}},"required":["field","op"],"description":"A field predicate. missing means database null only. present includes false, zero, blank text and empty collections. empty excludes null and matches empty or space-only text, an empty array or an empty JSON object. Operators depend on the field type; use filterCapabilities rather than assuming every listed operator applies.","oneOf":[{"properties":{"op":{"enum":["missing","present","empty"]}},"not":{"required":["value"]}},{"properties":{"op":{"enum":["eq"]}},"required":["value"]},{"properties":{"op":{"enum":["in"]},"value":{"type":"array","minItems":1,"maxItems":100,"items":{"type":["string","number","boolean"]}}},"required":["value"]},{"properties":{"op":{"enum":["containsText"]},"value":{"type":"string"}},"required":["value"]},{"properties":{"field":{"enum":["region"]},"op":{"enum":["matchesRegion"]},"value":{"type":"string","minLength":1,"pattern":"\\S"}},"required":["value"]},{"properties":{"op":{"enum":["lt","lte","gt","gte"]},"value":{"type":["number","string"]}},"required":["value"]},{"properties":{"op":{"enum":["containsAny","containsAll"]},"value":{"type":"array","minItems":1,"maxItems":100,"items":{}}},"required":["value"]},{"properties":{"op":{"enum":["contains"]},"value":{"type":"integer"}},"required":["value"]},{"properties":{"op":{"enum":["overlaps"]},"value":{"type":"array","minItems":2,"maxItems":2,"items":{"type":["integer","null"]}}},"required":["value"]}]},"CanonicalFilterRelated":{"type":"object","additionalProperties":false,"properties":{"related":{"type":"object","additionalProperties":false,"properties":{"relation":{"type":"string","enum":["organization","activity","activities","sessions"],"description":"Organizations expose activities/sessions; activities expose organization/sessions; sessions expose organization/activity. Use the current capability map. A session direct organization wins; its activity supplies the organization only when direct ownership is absent. Organization descendant chains retain that owner."},"match":{"type":"string","enum":["any","none"],"description":"any requires a matching related record; none requires no matching related record in the disclosed population."},"where":{"$ref":"#/components/schemas/CanonicalFilter"}},"required":["relation","match","where"]}},"required":["related"]},"CanonicalFilterRadius":{"type":"object","additionalProperties":false,"properties":{"radius":{"type":"object","additionalProperties":false,"properties":{"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"radiusMeters":{"type":"number","exclusiveMinimum":0}},"required":["latitude","longitude","radiusMeters"]}},"required":["radius"],"description":"Strict distance predicate using the selected entity own valid, disclosed coordinates with coordinate_precision exact, building, parcel or street. Includes points on the radius boundary. Missing, masked, approximate and unknown-precision locations do not match. No parent location fallback or possible-area match is used."},"CanonicalFilterPrice":{"type":"object","additionalProperties":false,"properties":{"price":{"type":"object","additionalProperties":false,"properties":{"minimum":{"type":"number","minimum":0},"maximum":{"type":"number","minimum":0},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"basis":{"type":"string","enum":["hour","day","week","month","session"]}},"required":["currency","basis"],"anyOf":[{"required":["minimum"]},{"required":["maximum"]}]}},"required":["price"],"description":"Session scope only. Match one recorded tuition quote with the requested currency and basis and at least one inclusive finite nonnegative bound. minimum must not exceed maximum. Missing amount, currency or basis cannot match; zero can. No currency conversion, rate conversion, attendance multiplication, fees, care amounts or comparable total is inferred. Separate price predicates can match different quotes."},"CanonicalFilterSchedule":{"type":"object","additionalProperties":false,"properties":{"schedule":{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["overlap","covers"],"description":"With explicit dates or a from/to range, overlap matches at least one requested attendance date and covers matches every requested attendance date. A time point must fall within known daily hours; a time window must overlap in overlap mode or be fully covered by one source window in covers mode. Without date limits, either mode matches any qualifying configuration and any requested weekday."},"dates":{"type":"array","items":{"type":"string","format":"date"},"uniqueItems":true,"minItems":1,"maxItems":366},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"daysOfWeek":{"type":"array","items":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]},"uniqueItems":true,"minItems":1,"maxItems":7,"description":"Lowercase weekdays, allowed with from/to or without date limits; disallowed with explicit dates. Without date limits, any requested weekday must have a real, non-excluded occurrence in the same configuration as any requested hours."},"atTime":{"type":"string","pattern":"^(?:[01][0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?$","description":"A local time point in HH:mm or HH:mm:ss, exclusive with startTime/endTime. Opening is inclusive and closing is exclusive."},"startTime":{"type":"string","pattern":"^(?:[01][0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?$"},"endTime":{"type":"string","pattern":"^(?:(?:[01][0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?|24:00(?::00)?)$"},"timeZone":{"type":"string","default":"venueLocal","minLength":1,"description":"venueLocal or a valid IANA time zone. venueLocal compares stored civil dates/clocks and does not require a known source zone. IANA requests require explicit dates or from/to plus atTime or a startTime/endTime window, compare instants, and require the session own known IANA zone. Ambiguous or nonexistent request endpoints are rejected; ambiguous/nonexistent source endpoints do not match. Local is not accepted."},"includeCare":{"type":"boolean","default":false,"description":"Point or window requests only. Extend daily hours with explicitly available care and known care clocks, subject to care-hour access (Starter or higher). Missing care facts never extend a window. Invalid optional care endpoints fall back to valid core hours; care cannot rescue an invalid core window."}},"required":["mode"],"oneOf":[{"required":["dates"],"not":{"anyOf":[{"required":["from"]},{"required":["to"]},{"required":["daysOfWeek"]}]}},{"required":["from","to"],"not":{"required":["dates"]}},{"not":{"anyOf":[{"required":["dates"]},{"required":["from"]},{"required":["to"]}]},"anyOf":[{"required":["daysOfWeek"]},{"required":["atTime"]},{"required":["startTime"]}]}],"dependentRequired":{"from":["to"],"to":["from"],"startTime":["endTime"],"endTime":["startTime"]},"allOf":[{"if":{"required":["atTime"]},"then":{"not":{"anyOf":[{"required":["startTime"]},{"required":["endTime"]}]}}},{"if":{"required":["includeCare"],"properties":{"includeCare":{"const":true}}},"then":{"anyOf":[{"required":["atTime"]},{"required":["startTime","endTime"]}]}},{"if":{"required":["timeZone"],"properties":{"timeZone":{"not":{"const":"venueLocal"}}}},"then":{"allOf":[{"anyOf":[{"required":["atTime"]},{"required":["startTime","endTime"]}]},{"anyOf":[{"required":["dates"]},{"required":["from","to"]}]}]}}]}},"required":["schedule"],"description":"Session scope only. Supply explicit dates, an inclusive from/to range with optional lowercase weekdays, or no date limits. Explicit dates cannot combine with daysOfWeek. At least one date, weekday, time point, or time window is required. Dated matching uses exact explicit attendance or weekly rules with exclusions; broad source date ranges do not establish exact attendance. At most 366 selected dates spanning at most 366 days; dates use years 0001–9999. Without date limits, known daily hours can satisfy a time-only request even when attendance dates are unknown; weekdays require actual non-excluded occurrences in the same configuration as requested hours. Omit clocks for date/weekday-only matching, supply atTime for a point, or supply startTime and a later endTime within the same day for a window. Point opening is inclusive and closing exclusive; adjacent windows do not overlap. Only endTime may be 24:00 or 24:00:00. Timed matching requires recorded daily source hours. Parent hours/time zones never fill unknown session facts."},"CanonicalFilterCapabilities":{"type":"object","additionalProperties":false,"properties":{"fields":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"field":{"type":"string"},"type":{"type":"string"},"description":{"type":"string","description":"Optional interpretation guidance for filter-only fields."},"operators":{"type":"array","items":{"type":"string","enum":["eq","in","missing","present","empty","lt","lte","gt","gte","containsText","matchesRegion","containsAny","containsAll","contains","overlaps"]}}},"required":["field","type","operators"]}},"relations":{"type":"object","additionalProperties":{"type":"string","enum":["organization","activity","session"]},"description":"Available relation name to target entity kind; preview disclosure can remove target kinds."},"predicates":{"type":"array","items":{"type":"string","enum":["all","any","field","related","radius","price","schedule"]}},"maximumDepth":{"type":"integer","minimum":1},"maximumPredicates":{"type":"integer","minimum":1,"description":"Total tree nodes, including groups."},"maximumValues":{"type":"integer","minimum":1},"maximumBytes":{"type":"integer","minimum":1},"missingMeans":{"const":"null"},"priceRequires":{"type":"array","items":{"type":"string"}},"scheduleTimeZones":{"type":"array","items":{"type":"string","enum":["venueLocal","IANA"]}}},"required":["fields","relations","predicates","maximumDepth","maximumPredicates","maximumValues","maximumBytes","missingMeans","priceRequires","scheduleTimeZones"],"description":"Live capability metadata for the disclosed entity projection. Current tree limits are 8192 encoded bytes, depth 8, 64 total nodes and 100 membership values. Field-specific typed values, relation availability, special-predicate field permissions and schedule constraints are still validated for every request."},"CanonicalSchemaColumn":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"dataType":{"type":"string"},"nullable":{"type":"boolean"}},"required":["name","dataType","nullable"]},"CanonicalSchemaTable":{"type":"object","properties":{"target_kind":{"type":"string","enum":["organization","activity","session","organization_score"]},"table":{"type":"string"},"columns":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalSchemaColumn"}},"filterCapabilities":{"$ref":"#/components/schemas/CanonicalFilterCapabilities"},"cached":{"type":"boolean"}},"required":["target_kind","table","columns"],"description":"Entity tables include filterCapabilities; organization_score describes SQL score columns and has no structured filter capabilities. Preview exposes only permitted entity tables and columns."},"CanonicalSchemaResponse":{"type":"object","properties":{"success":{"const":true},"data":{"type":"object","properties":{"tables":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalSchemaTable"}},"tier":{"type":"string"},"sourceClass":{"const":"canonical"},"locationColumns":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalSchemaColumn"}},"locationColumnsCondition":{"type":"string"},"resultLimit":{"type":"integer","minimum":1},"preview":{"type":"object","properties":{"sample":{"const":true},"pageSize":{"type":"integer","minimum":1}},"required":["sample","pageSize"]}},"required":["tables","tier","sourceClass"]}},"required":["data","success"]},"FamilyFeedPost":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"topic":{"type":"string"},"headline":{"type":"string"},"body":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"},"signal":{"type":["string","null"],"enum":["like","dislike","dont_show_again",null]}},"required":["id","kind","topic","headline","body","reason","signal"],"additionalProperties":false},"FamilyFeedEditionKey":{"type":"object","properties":{"date":{"type":"string","format":"date"},"slot":{"type":"string","enum":["morning","evening"]}},"required":["date","slot"],"additionalProperties":false},"FamilyFeedEdition":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"date":{"type":"string","format":"date"},"slot":{"type":"string","enum":["morning","evening"]},"publishedAt":{"type":"string","format":"date-time"},"posts":{"type":"array","items":{"$ref":"#/components/schemas/FamilyFeedPost"}}},"required":["id","date","slot","publishedAt","posts"],"additionalProperties":false},"HallPassRunMoney":{"type":"object","additionalProperties":false,"required":["amountCents","currency"],"properties":{"amountCents":{"type":"integer"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"}}},"HallPassRunError":{"type":"object","required":["error","message"],"properties":{"error":{"const":true},"message":{"type":"string","description":"A sentence you can show staff as is."},"data":{"type":"null"}}},"HallPassRunInput":{"type":"object","additionalProperties":false,"required":["idempotencyKey"],"description":"What staff ask Hallpass to do. `kind` defaults to `general`; send exactly the details object for the kind. A run places the order by default, spending up to `maxSpend` or the staff cap; `rehearsal` stops at the checkout total and orders nothing. While the staff cap is 0 only rehearsals start.","properties":{"idempotencyKey":{"type":"string","format":"uuid","description":"One key per run for this staff member. A resend with the same details returns the run; different details answer 409."},"kind":{"type":"string","enum":["general","camp_booking"],"description":"Defaults to `general`."},"rehearsal":{"type":"boolean","default":false,"description":"Stop at the checkout total and order nothing. Off by default: a run places the order."},"maxSpend":{"oneOf":[{"$ref":"#/components/schemas/HallPassRunMoney"},{"type":"null"}],"description":"A USD spending limit up to HALLPASS_STAFF_MAX_SPEND_CENTS. Leave it out to spend up to that cap; send zero (or set `rehearsal`) for a rehearsal."},"autoAcceptDecisions":{"type":"boolean","description":"Let Hallpass accept routine questions within the limit. Totals, signatures and provider accounts always wait for staff."},"deadlineMinutes":{"type":"integer","minimum":10,"maximum":2880,"description":"Defaults to 120."},"general":{"type":"object","additionalProperties":false,"required":["instruction"],"properties":{"instruction":{"type":"string","minLength":1,"maxLength":4000},"startUrl":{"type":["string","null"],"description":"An https page to start from."},"subjects":{"type":"array","maxItems":10,"items":{"type":"object","additionalProperties":false,"required":["role","fields"],"properties":{"role":{"type":"string","pattern":"^[a-z][a-z_]{0,31}$","description":"Such as `traveler` or `recipient`."},"fields":{"type":"object","additionalProperties":{"type":"string"},"description":"Keys from the Hallpass subject vocabulary (`full_name`, `email_address`, `phone_number`, `street_address`, `postal_code`, `departure_airport`, …), as `/openapi/hallpass.json` lists them. Every field sent is shared with the provider."}}}},"answers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["key","label","value"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"type":["string","boolean","number"]}}}},"references":{"type":"array","maxItems":20,"items":{"type":"object","additionalProperties":false,"required":["kind","label","value"],"properties":{"kind":{"type":"string","enum":["url","note","catalog"]},"label":{"type":"string"},"value":{"type":"string"}}}}}},"campBooking":{"type":"object","additionalProperties":false,"required":["sessionId","attendee","guardian"],"properties":{"sessionId":{"type":"string","format":"uuid","description":"A catalog session; Hallpass gets its organization, dates, price and registration link."},"attendee":{"type":"object","additionalProperties":false,"required":["firstName","lastName"],"properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"birthDate":{"type":"string","format":"date"},"grade":{"type":"string"},"allergies":{"type":"string"}}},"guardian":{"type":"object","additionalProperties":false,"required":["name","email"],"properties":{"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"}}},"answers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["key","label","value"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"type":["string","boolean","number"]}}}},"allowWaitlist":{"type":"boolean"}}},"accounts":{"type":"array","maxItems":5,"description":"Site accounts for Pilgrim to sign in with, at most 5. Refused while HALLPASS_SECRETS_KEY is unset, and through Overseer. The username and password are sealed (AES-256-GCM) the moment they are recorded, never stored or shown in the clear, handed to OS Pilgrim as session account entries for their site only, and erased when the run ends or reaches its deadline. A run that attaches accounts runs only in Automatic mode, and a request whose text repeats a username or password is refused.","items":{"type":"object","additionalProperties":false,"required":["site","username","password"],"properties":{"site":{"type":"string","format":"uri","maxLength":2048,"description":"The https page the account signs in on, such as https://www.doordash.com; no port or credentials; any query or fragment is dropped. The account covers that site's registered domain."},"label":{"type":["string","null"],"maxLength":80,"description":"How staff name the account, such as DoorDash."},"username":{"type":"string","minLength":1,"maxLength":256,"description":"The username or email, trimmed. Shown afterwards only masked."},"password":{"type":"string","minLength":1,"maxLength":1024,"writeOnly":true,"description":"Kept exactly as typed. Never returned."}}}}}},"HallPassRunReplay":{"type":"object","additionalProperties":false,"required":["kind","rehearsal","maxSpend","autoAcceptDecisions","deadlineMinutes","general","campBooking","accounts"],"description":"The request that starts this run again, in the shape `POST /api/hallpass/runs` takes, rebuilt from the run's task: send it with a new `idempotencyKey` to repeat the run exactly, or edit it first. `maxSpend` is the limit the run ran with (the staff cap applied when none was given) and `deadlineMinutes` the minutes it was given. Accounts come back as site and label only: usernames and passwords are sealed and never returned, so a replay attaches them afresh.","properties":{"kind":{"type":"string","enum":["general","camp_booking"],"description":"Defaults to `general`."},"rehearsal":{"type":"boolean","description":"True when the run spent nothing."},"maxSpend":{"oneOf":[{"$ref":"#/components/schemas/HallPassRunMoney"},{"type":"null"}],"description":"The limit the run ran with; null for a rehearsal."},"autoAcceptDecisions":{"type":"boolean","description":"Let Hallpass accept routine questions within the limit. Totals, signatures and provider accounts always wait for staff."},"deadlineMinutes":{"type":"integer","description":"The minutes the run was given."},"general":{"oneOf":[{"type":"object","additionalProperties":false,"required":["instruction"],"properties":{"instruction":{"type":"string","minLength":1,"maxLength":4000},"startUrl":{"type":["string","null"],"description":"An https page to start from."},"subjects":{"type":"array","maxItems":10,"items":{"type":"object","additionalProperties":false,"required":["role","fields"],"properties":{"role":{"type":"string","pattern":"^[a-z][a-z_]{0,31}$","description":"Such as `traveler` or `recipient`."},"fields":{"type":"object","additionalProperties":{"type":"string"},"description":"Keys from the Hallpass subject vocabulary (`full_name`, `email_address`, `phone_number`, `street_address`, `postal_code`, `departure_airport`, …), as `/openapi/hallpass.json` lists them. Every field sent is shared with the provider."}}}},"answers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["key","label","value"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"type":["string","boolean","number"]}}}},"references":{"type":"array","maxItems":20,"items":{"type":"object","additionalProperties":false,"required":["kind","label","value"],"properties":{"kind":{"type":"string","enum":["url","note","catalog"]},"label":{"type":"string"},"value":{"type":"string"}}}}}},{"type":"null"}]},"campBooking":{"oneOf":[{"type":"object","additionalProperties":false,"required":["sessionId","attendee","guardian"],"properties":{"sessionId":{"type":"string","format":"uuid","description":"A catalog session; Hallpass gets its organization, dates, price and registration link."},"attendee":{"type":"object","additionalProperties":false,"required":["firstName","lastName"],"properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"birthDate":{"type":["string","null"],"format":"date"},"grade":{"type":["string","null"]},"allergies":{"type":["string","null"]}},"description":"Optional fields are null when the run did not carry them."},"guardian":{"type":"object","additionalProperties":false,"required":["name","email"],"properties":{"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":["string","null"]}}},"answers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["key","label","value"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"type":["string","boolean","number"]}}}},"allowWaitlist":{"type":"boolean"}}},{"type":"null"}]},"accounts":{"type":"array","description":"The attached accounts by site and label, in order; no username or password.","items":{"type":"object","additionalProperties":false,"required":["site","label"],"properties":{"site":{"type":"string","format":"uri"},"label":{"type":["string","null"]}}}}}},"HallPassRunSettings":{"type":"object","additionalProperties":false,"required":["spendCap","ordersEnabled","accountsEnabled"],"description":"What a staff run may spend in this deployment, and whether it may attach site accounts.","properties":{"spendCap":{"$ref":"#/components/schemas/HallPassRunMoney"},"ordersEnabled":{"type":"boolean","description":"False when the cap is 0: only rehearsals start."},"accountsEnabled":{"type":"boolean","description":"True when the deployment holds HALLPASS_SECRETS_KEY, so a run may attach site accounts; false refuses any run that does."}}},"HallPassRun":{"type":"object","additionalProperties":false,"required":["id","kind","summary","rehearsal","maxSpend","autoAcceptDecisions","requesterUserId","request","state","refusal","mode","stage","hold","decision","decisions","receipt","failure","uncertainty","accounts","replay","pollAfterMs","deadlineAt","createdAt","updatedAt"],"description":"A staff run as staff see it. `state` is `submitting` until Hallpass acknowledges the task (each read resends it), `refused` if Hallpass turned it down, and otherwise Hallpass’s task state.","properties":{"id":{"type":"string","format":"uuid","description":"Also the Hallpass request ID."},"kind":{"type":"string","enum":["general","camp_booking"],"x-open-enum":true},"summary":{"type":"string"},"rehearsal":{"type":"boolean","description":"True when the run may not pay."},"maxSpend":{"$ref":"#/components/schemas/HallPassRunMoney"},"autoAcceptDecisions":{"type":"boolean"},"requesterUserId":{"type":["string","null"],"format":"uuid"},"request":{"type":"object","additionalProperties":false,"required":["instruction","startUrl","sessionId","merchant"],"properties":{"instruction":{"type":["string","null"]},"startUrl":{"type":["string","null"]},"sessionId":{"type":["string","null"],"format":"uuid"},"merchant":{"type":["string","null"],"description":"The camp, for a camp booking run."}}},"state":{"type":"string","enum":["submitting","refused","accepted","running","awaiting_decision","confirmed","waitlisted","failed","uncertain","cancelled"],"x-open-enum":true},"refusal":{"type":["string","null"]},"mode":{"type":["string","null"],"enum":["fast","automatic",null],"x-open-enum":true},"stage":{"type":["string","null"],"enum":["locating","filling","reviewing_total","paying","confirming",null],"x-open-enum":true},"hold":{"description":"Why a running run is waiting on something nobody can answer: Pilgrim holding an earlier task for a person's review, Pilgrim's assistance switched off at its Mac, or Hallpass retrying its worker. `null` while the run moves on its own.","oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["code","message","since"],"properties":{"code":{"type":"string","enum":["pilgrim_queue_held","pilgrim_assistance_off","executor_retrying","pilgrim_busy"],"x-open-enum":true},"message":{"type":"string","minLength":1,"maxLength":500,"description":"What the run waits for, written for the requester."},"since":{"type":"string","format":"date-time"}}}]},"decision":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["decisionId","code","message","options","proposedOptionId","expiresAt","screenshot"],"properties":{"decisionId":{"type":"string","format":"uuid"},"code":{"type":"string","enum":["unknown_question","choose_option","confirm_total","signature_required","provider_account_required","session_changed","unverified_step","answer_required"],"x-open-enum":true},"message":{"type":"string"},"options":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["optionId","label","total"],"properties":{"optionId":{"type":"string"},"label":{"type":"string"},"total":{"oneOf":[{"$ref":"#/components/schemas/HallPassRunMoney"},{"type":"null"}]}}}},"proposedOptionId":{"type":["string","null"]},"expiresAt":{"type":"string","format":"date-time"},"screenshot":{"description":"The provider’s page as Hallpass last saw it, for an `unverified_step` decision; null otherwise.","oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["mediaType","data","width","height","capturedAt"],"properties":{"mediaType":{"type":"string","enum":["image/jpeg","image/png"]},"data":{"type":"string","description":"Base64 of the image."},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"capturedAt":{"type":"string","format":"date-time"}}}]}}}]},"decisions":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["decisionId","code","outcome","optionId","total","decidedBy","decidedAt"],"properties":{"decisionId":{"type":"string","format":"uuid"},"code":{"type":"string"},"outcome":{"type":"string","enum":["accepted","declined","expired"],"x-open-enum":true},"optionId":{"type":["string","null"]},"total":{"oneOf":[{"$ref":"#/components/schemas/HallPassRunMoney"},{"type":"null"}],"description":"The total staff confirmed, for a confirm_total decision."},"decidedBy":{"type":["string","null"],"enum":["requester","auto",null],"x-open-enum":true},"decidedAt":{"type":"string","format":"date-time"}}}},"receipt":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["providerReference","providerStatus","merchant","paymentStatus","amount","amountDue","lineItems","evidence","confirmedAt","bookedSession","fulfillment"],"properties":{"providerReference":{"type":"string"},"providerStatus":{"type":"string"},"merchant":{"type":"string"},"paymentStatus":{"type":"string","enum":["charged","not_required","deferred"],"x-open-enum":true},"amount":{"oneOf":[{"$ref":"#/components/schemas/HallPassRunMoney"},{"type":"null"}]},"amountDue":{"oneOf":[{"$ref":"#/components/schemas/HallPassRunMoney"},{"type":"null"}]},"lineItems":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["kind","label","amount"],"properties":{"kind":{"type":"string"},"label":{"type":"string"},"amount":{"$ref":"#/components/schemas/HallPassRunMoney"}}}},"evidence":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["kind","summary","capturedAt"],"properties":{"kind":{"type":"string"},"summary":{"type":"string"},"capturedAt":{"type":"string","format":"date-time"}}}},"confirmedAt":{"type":"string","format":"date-time"},"bookedSession":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["sessionId","label","startDate","endDate"],"properties":{"sessionId":{"type":"string","format":"uuid"},"label":{"type":"string"},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"}}}]},"fulfillment":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["summary","startsAt","endsAt"],"properties":{"summary":{"type":"string"},"startsAt":{"type":["string","null"],"format":"date-time"},"endsAt":{"type":["string","null"],"format":"date-time"}}}]}}}]},"failure":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["code","message","retryable","providerTotal"],"properties":{"code":{"type":"string","description":"A Hallpass failure code; `stopped_before_payment` ends a rehearsal at the total in `providerTotal`."},"message":{"type":"string"},"retryable":{"type":"boolean"},"providerTotal":{"oneOf":[{"$ref":"#/components/schemas/HallPassRunMoney"},{"type":"null"}]}}}]},"uncertainty":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["suspected","lastStage","message"],"properties":{"suspected":{"type":"array","items":{"type":"string"}},"lastStage":{"type":"string"},"message":{"type":"string"}}}]},"accounts":{"type":"array","description":"The run's attached site accounts by site, label and masked username, and whether each is held for Pilgrim, delivered to it, or erased. Never a password.","items":{"type":"object","additionalProperties":false,"required":["site","label","username","state"],"properties":{"site":{"type":"string","format":"uri"},"label":{"type":["string","null"]},"username":{"type":"string","description":"Masked, such as r…@example.com."},"state":{"type":"string","enum":["held","delivered","erased"],"x-open-enum":true}}}},"replay":{"$ref":"#/components/schemas/HallPassRunReplay"},"pollAfterMs":{"type":["integer","null"],"description":"How long to wait before reading the run again; null once nothing will change."},"deadlineAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"HallPassRunActivity":{"type":"object","additionalProperties":false,"required":["lines","after"],"description":"A staff run's live log after a sequence, oldest first.","properties":{"lines":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["sequence","code","summary","at"],"properties":{"sequence":{"type":"integer","minimum":1},"code":{"type":"string"},"summary":{"type":"string"},"at":{"type":"string","format":"date-time"}}}},"after":{"type":"integer","minimum":0,"description":"The last sequence returned, or the one asked for when nothing is new."}}},"HallPassPlan":{"type":"object","additionalProperties":false,"required":["kind","reason","sessions","missing"],"description":"How Hallpass would read a request before anyone approves it. A catalog session is a camp booking; a page on a listed organization's site offers its current sessions while the request stays general; anything else is general.","properties":{"kind":{"type":"string","enum":["general","camp_booking"],"x-open-enum":true},"reason":{"type":"string","description":"A sentence you can show staff as is."},"sessions":{"type":"array","maxItems":10,"items":{"type":"object","additionalProperties":false,"required":["sessionId","sessionName","organizationName","startDate","endDate"],"properties":{"sessionId":{"type":"string","format":"uuid"},"sessionName":{"type":["string","null"]},"organizationName":{"type":"string"},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"}}}},"missing":{"type":"array","items":{"type":"string"},"description":"What the typed variant still needs, as sentences."}}},"OverseerReviewSummary":{"type":"object","properties":{"id":{"format":"uuid","type":"string"},"version":{"minimum":1,"type":"integer"},"latestVersion":{"type":"integer","minimum":1},"kind":{"enum":["organization","activity","session"]},"label":{"type":"string"},"status":{"enum":["applied","not_applied","revalidation_requested","reverting","reverted","revert_failed"]},"auditStatus":{"enum":["unreviewed","reviewed","changes_requested"]},"proposalCreatedAt":{"description":"Creation time of this immutable update version; createdAt is the identity creation time.","format":"date-time","type":"string"},"revalidationReason":{"type":"string"},"entityId":{"type":"string"},"activityId":{"type":"string"}},"required":["id","version","latestVersion","kind","label","status","auditStatus","proposalCreatedAt","entityId","activityId"]},"CanonicalStockImage":{"type":"object","additionalProperties":false,"description":"Public attribution for an illustrative stock photograph; it does not claim to depict the organization.","properties":{"provider":{"type":"string"},"photoId":{"type":"string"},"photoPageUrl":{"type":"string","format":"uri"},"photographerName":{"type":"string"},"photographerUrl":{"type":"string","format":"uri"},"licenseUrl":{"type":"string","format":"uri"}},"required":["provider","photoPageUrl","photographerName","licenseUrl"]},"CanonicalResolvedCover":{"type":"object","description":"Display cover resolved through the organization hierarchy. sourceEntity identifies its ultimate owner; inheritance does not add gallery membership. Stock is the final organization fallback.","properties":{"displayUrl":{"description":"Original remote URL or a protected relative organization brand-asset URL.","format":"uri-reference","type":"string"},"height":{"minimum":1,"type":["integer","null"]},"id":{"format":"uuid","type":"string"},"kind":{"type":"string"},"label":{"type":"string"},"width":{"minimum":1,"type":["integer","null"]},"isStock":{"type":"boolean","description":"Derived from retained stock metadata."},"stock":{"anyOf":[{"$ref":"#/components/schemas/CanonicalStockImage"},{"type":"null"}]},"sourceEntity":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string","enum":["organization","activity","session"]},"id":{"type":"string","format":"uuid"}},"required":["kind","id"]},"inherited":{"type":"boolean"}},"required":["id","displayUrl","label","kind","width","height","isStock","stock","sourceEntity","inherited"]},"OverseerStockImage":{"type":"object","additionalProperties":false,"description":"Immutable stock import metadata copied from the verified import receipt. Only organization gallery photos may carry it.","properties":{"provider":{"type":"string"},"photo_id":{"type":"string"},"photo_page_url":{"type":"string"},"photographer_name":{"type":"string"},"photographer_url":{"type":"string"},"license_url":{"type":"string"},"original_url":{"type":"string"},"sha256":{"type":"string"},"object_key":{"type":"string"},"imported_at":{"type":"string","format":"date-time"}},"required":["provider","photo_page_url","photographer_name","license_url","original_url","sha256","object_key","imported_at"]},"HallPassRunTraceEvent":{"type":"object","additionalProperties":false,"required":["id","at","kind","name"],"description":"One event about the run, as it was shipped to Axiom: one of OS Pilgrim's telemetry events about the run's Pilgrim task (already redacted of attached values), or one of Hallpass's or the API's rows about the run (`kind` `hallpass`, which carry `runId`, `decidedBy` and `sender` and neither `launch` nor `sequence`).","properties":{"id":{"type":"string","description":"The event id, to de-duplicate on: Pilgrim's launch and sequence, or Hallpass's `hallpass:<run id>:<seq>`."},"at":{"type":"string","format":"date-time"},"launch":{"type":"string","description":"Pilgrim's launch; absent on Hallpass rows."},"sequence":{"type":"integer","minimum":0,"description":"Pilgrim's sequence within the launch; absent on Hallpass rows, which order by `at`."},"kind":{"type":"string","enum":["launched","state","journal","helper","planner","pageTools","task","action","inference","decision","liveScreen","shipper","hallpass"]},"name":{"type":"string"},"outcome":{"type":"string","description":"Pilgrim's `succeeded` or `failed`; on Hallpass rows the run's final state (`settled`) or a decision's `accept` or `decline` (`decision_answered`)."},"code":{"type":"string","description":"A Pilgrim outcome code, or a Hallpass hold, decision or failure code."},"seconds":{"type":"number"},"step":{"type":"integer"},"operation":{"type":"string"},"role":{"type":"string"},"model":{"type":"string"},"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"},"answer":{"type":"string"},"value":{"type":"string","description":"Free detail, such as what lay under a refused click (roles only), or Hallpass's `k=v` details (a decision and option id, an attempt, a reason keyword, a payment amount)."},"text":{"type":"string","description":"The run-log line, redacted by Pilgrim."},"phases":{"type":"object","additionalProperties":{"type":"number"},"description":"A helper operation's phase timings in seconds."},"attempt":{"type":"integer","description":"Pilgrim's attempt within the task, when the event carries one."},"turn":{"type":"string","description":"Pilgrim's planner turn id, when the event belongs to one."},"counts":{"type":"object","additionalProperties":{"type":"integer"},"description":"Pilgrim's counters at the event (for example clicks and refused clicks)."},"runId":{"type":"string","format":"uuid","description":"The staff run id; Hallpass rows only."},"decidedBy":{"type":"string","description":"Who acted, on Hallpass rows: `person`, `auto`, `key:<key id>` or, on `run_created`, `user:<user id>`."},"sender":{"type":"string","enum":["hallpass","apis"],"description":"Which service wrote the row; Hallpass rows only."}}},"HallPassRunTrace":{"type":"object","additionalProperties":false,"required":["source","events","after","complete"],"description":"A page of a staff run's trace, oldest first.","properties":{"taskId":{"type":"string","format":"uuid","description":"The Pilgrim task id behind the run, the `task` of its Pilgrim events; absent until Hallpass names one."},"source":{"type":"string","enum":["axiom"]},"events":{"type":"array","maxItems":1000,"items":{"$ref":"#/components/schemas/HallPassRunTraceEvent"}},"after":{"type":"string","description":"The last event's time, to pass back; empty when the page was empty and the request named no time."},"complete":{"type":"boolean","description":"False when the page was full and more may follow at once."}}},"CrawlerCampaignProfileStage":{"type":"object","required":["stage","count","error_count","total_ms","max_ms","active","oldest_active_ms"],"properties":{"stage":{"type":"string"},"count":{"type":"integer","minimum":0},"error_count":{"type":"integer","minimum":0},"total_ms":{"type":"number","minimum":0},"max_ms":{"type":"number","minimum":0},"active":{"type":"integer","minimum":0},"oldest_active_ms":{"type":"number","minimum":0}},"additionalProperties":false},"CrawlerCampaignProfileResources":{"type":"object","required":["memory_bytes","tasks"],"properties":{"cpu_cores":{"type":"number","minimum":0},"memory_bytes":{"type":"integer","minimum":0},"tasks":{"type":"integer","minimum":0}},"additionalProperties":false},"CrawlerCampaignRuntimeProfile":{"type":"object","required":["started_at","observed_at","running","stages","slots"],"properties":{"started_at":{"type":"string","format":"date-time"},"observed_at":{"type":"string","format":"date-time"},"running":{"type":"boolean"},"stages":{"type":"array","items":{"$ref":"#/components/schemas/CrawlerCampaignProfileStage"}},"slots":{"type":"object","additionalProperties":{"type":"integer","minimum":0}},"resources":{"$ref":"#/components/schemas/CrawlerCampaignProfileResources"}},"additionalProperties":false},"CrawlerCampaignWorkerProfile":{"type":"object","required":["worker_id","observed_at","stale","profile"],"properties":{"worker_id":{"type":"string","format":"uuid"},"observed_at":{"type":"string","format":"date-time"},"stale":{"type":"boolean"},"profile":{"$ref":"#/components/schemas/CrawlerCampaignRuntimeProfile"}},"additionalProperties":false},"CrawlerCampaignPerformance":{"type":"object","required":["workers"],"properties":{"workers":{"type":"array","items":{"$ref":"#/components/schemas/CrawlerCampaignWorkerProfile"}}},"additionalProperties":false}},"securitySchemes":{"AccountCredential":{"description":"Current account credential. Named machine keys cannot execute SQL. Intelligence alternatively uses its signed session cookie; cookie POST requests require the session-bound CSRF token and trusted origin.","in":"header","name":"x-api-key","type":"apiKey"},"ApiKeyAuth":{"description":"Account credential or named machine key for integrations. Keep it server-side and send it in x-api-key. Intelligence browser requests separately support the existing signed session cookie; cookie mutations require CSRF verification.","in":"header","name":"x-api-key","type":"apiKey"}}},"info":{"description":"Read-only external integration access to the canonical School’s Out catalog and scores. Legacy Insights datasets require ADMIN access. SQL, generic database access, physical table names, and writes are not part of the public API. Product and operator operations are marked x-internal and retain their own credential, plan, role, origin and CSRF requirements.","title":"School’s Out developer API","version":"0.2.0"},"openapi":"3.1.0","paths":{"/api/hallpass/settings":{"get":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Read staff run settings","description":"What a full order may spend in this deployment (HALLPASS_STAFF_MAX_SPEND_CENTS). With `ordersEnabled` false, only rehearsals start.","responses":{"200":{"description":"The settings.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["settings"],"properties":{"settings":{"$ref":"#/components/schemas/HallPassRunSettings"}}}}},"example":{"success":true,"data":{"settings":{"spendCap":{"amountCents":10000,"currency":"USD"},"ordersEnabled":true}}}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Read staff run settings","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/hallpass/settings\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/activities":{"get":{"summary":"Query canonical activities","description":"Internal product list of canonical activities. Legacy parameters and filter JSON combine with AND before exact filtered counts and pagination. Filters use this entity own disclosed fields; categories and locations do not inherit. Records use the same public projection as detail reads, with own image_urls and bounded parent summaries. Empty results mean no disclosed catalog root matched, not verified provider absence or registration availability. Ordinary permitted JSON records include resolved_cover with the ultimate source entity, inheritance flag, and structured stock attribution. Owned gallery and image compatibility fields retain their existing meaning.","tags":["Canonical"],"x-internal":true,"x-auth":"Account session, account credential or named integration key; Starter or higher. Fields follow current plan and preview disclosure.","parameters":[{"description":"Search visible name, description, skill_level, format, and seasonality fields. Repeat up to five terms; the terms combine with OR.","explode":true,"in":"query","name":"q","required":false,"schema":{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Case-insensitive exact city name or its lowercase hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Case-insensitive exact region, such as a state abbreviation.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on this activity; no parent inheritance.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Returns records whose stated grade range includes this grade. Use -1 for pre-K and 0 for kindergarten.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Visible sort field; omitted or unavailable fields use updated_at. Score ordering uses prepared scores.","in":"query","name":"orderBy","required":false,"schema":{"type":"string","enum":["name","score","rating","created_at","updated_at"]}},{"description":"Sort direction; defaults to desc.","in":"query","name":"order","required":false,"schema":{"enum":["asc","desc"],"type":"string"}},{"description":"One-based page number.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}},{"description":"Page size from 1 to 100 for JSON.","in":"query","name":"limit","required":false,"schema":{"default":24,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Set false to return counts and metadata with an empty activities array.","in":"query","name":"includeRows","required":false,"schema":{"default":true,"type":"boolean"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON predicate tree, sent once. Combines with all legacy filters using AND before rows, totals and facet counts are selected. Read /api/canonical/schema tables[*].filterCapabilities for visible fields, operators, relations and limits. Invalid/unknown/over-complex filters return 400; unavailable fields return 403, including in nonmatching branches. Do not broaden a failed request by dropping predicates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"organizationId","in":"query","required":false,"description":"Exact organization UUID. Selects the activity own organization.","schema":{"type":"string","format":"uuid"}},{"name":"skillLevel","in":"query","required":false,"description":"Exact recorded skill_level value.","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"Exact recorded format value.","schema":{"type":"string"}},{"name":"seasonality","in":"query","required":false,"description":"Exact recorded seasonality value.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success envelope with data.activities, total, unfilteredTotal, page, pageCount, limit, orderBy, order, columns, tier and sourceClass. total is the matched root count before pagination; includeRows=false leaves the array empty.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true},"data":{"type":"object","properties":{"activities":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalDetailRow"}},"total":{"type":"integer","minimum":0},"unfilteredTotal":{"type":"integer","minimum":0},"page":{"type":"integer","minimum":1},"pageCount":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"orderBy":{"type":"string"},"order":{"type":"string","enum":["asc","desc"]},"columns":{"type":"array","items":{"type":"string"}},"tier":{"type":"string"},"sourceClass":{"const":"canonical"}},"required":["activities","total","unfilteredTotal","page","pageCount","limit","orderBy","order","columns","tier","sourceClass"]}},"required":["success","data"]}}}},"400":{"description":"Invalid search, score bound, relationship ID, or structured filter; malformed/repeated filter JSON or a limit exceeded."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"403":{"description":"A filter field or relationship is unavailable under current field disclosure."},"500":{"$ref":"#/components/responses/ServerError"}},"x-curl-examples":[{"title":"Find activities under a typed filter","code":"curl --get \"https://apis.schoolsoutapp.com/api/activities\" -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" --data-urlencode 'filter={\"field\":\"age_range_years\",\"op\":\"contains\",\"value\":10}'"}]}},"/api/canonical/schema":{"get":{"summary":"Discover canonical columns and structured filter capabilities","description":"Internal product metadata for organization, activity and session reads and agent tools. Each entity table includes filterCapabilities with currently visible field types/operators, relation names and target kinds, predicate forms and bounded request limits. Hidden fields are omitted; preview metadata is limited to disclosed datasets and unmasked fields. organization_score describes SQL score columns and carries no structured filter capabilities. Metadata is authoritative for the current viewer and must not be reused for a different access scope. This endpoint returns schema metadata, not listing facts or evidence of verified availability.","tags":["Canonical"],"x-internal":true,"x-auth":"Authenticated account or named integration key. Returns metadata for the current effective plan; configured preview sessions receive only disclosed metadata.","responses":{"200":{"description":"Success envelope containing tier-filtered tables and capability metadata. Non-preview metadata also describes conditional location columns for canonical SQL; preview metadata includes its sample limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalSchemaResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Preview disclosure is not configured."}},"x-curl-examples":[{"title":"Discover permitted filter fields and operators","code":"curl \"https://apis.schoolsoutapp.com/api/canonical/schema\" -H \"x-api-key: $SCHOOLS_OUT_API_KEY\""}]}},"/api/sessions":{"get":{"summary":"Query canonical sessions","description":"Internal product list of canonical sessions. Legacy parameters and filter JSON combine with AND before exact filtered counts and pagination. Filters use this entity own disclosed fields; categories and locations do not inherit. Records use the same public projection as detail reads, with own image_urls and bounded parent summaries. Empty results mean no disclosed catalog root matched, not verified provider absence or registration availability. Ordinary permitted JSON records include resolved_cover with the ultimate source entity, inheritance flag, and structured stock attribution. Owned gallery and image compatibility fields retain their existing meaning.","tags":["Canonical"],"x-internal":true,"x-auth":"Account session, account credential or named integration key; Starter or higher. Fields follow current plan and preview disclosure.","parameters":[{"description":"Search visible name, notes, city, region, and registration_status fields. Repeat up to five terms; the terms combine with OR.","explode":true,"in":"query","name":"q","required":false,"schema":{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Case-insensitive exact city name or its lowercase hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Case-insensitive exact region, such as a state abbreviation.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on this session; no parent inheritance.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Returns records whose stated grade range includes this grade. Use -1 for pre-K and 0 for kindergarten.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Visible sort field; omitted or unavailable fields use updated_at. Score ordering uses prepared scores.","in":"query","name":"orderBy","required":false,"schema":{"type":"string","enum":["name","score","start_date","end_date","registration_open_date","city","created_at","updated_at"]}},{"description":"Sort direction; defaults to desc.","in":"query","name":"order","required":false,"schema":{"enum":["asc","desc"],"type":"string"}},{"description":"Set true to place past sessions after current and undated sessions before pagination, retaining orderBy/order and stable ID ties within each group. A session is past only when every disclosed schedule configuration has a known final date before today in UTC; a session ending today remains current. Missing or restricted schedules are not past. Defaults to false.","in":"query","name":"pastLast","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"One-based page number.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}},{"description":"Page size from 1 to 100 for JSON.","in":"query","name":"limit","required":false,"schema":{"default":24,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Set false to return counts and metadata with an empty sessions array.","in":"query","name":"includeRows","required":false,"schema":{"default":true,"type":"boolean"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON predicate tree, sent once. Combines with all legacy filters using AND before rows, totals and facet counts are selected. Read /api/canonical/schema tables[*].filterCapabilities for visible fields, operators, relations and limits. Invalid/unknown/over-complex filters return 400; unavailable fields return 403, including in nonmatching branches. Do not broaden a failed request by dropping predicates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"organizationId","in":"query","required":false,"description":"Exact organization UUID. Retained legacy membership filter accepts the session direct organization or its activity organization. Use a related organization predicate for direct-owner-first semantics.","schema":{"type":"string","format":"uuid"}},{"name":"activityId","in":"query","required":false,"description":"Exact session activity UUID.","schema":{"type":"string","format":"uuid"}},{"name":"registrationStatus","in":"query","required":false,"description":"Exact recorded registration_status when visible at the current plan.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Legacy inclusive lower date bound. Explicit attendance and weekly rules honor exclusions; source date ranges retain their broad overlap meaning. Use schedule for exact attendance/windows.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Legacy inclusive upper date bound. Explicit attendance and weekly rules honor exclusions; source date ranges retain their broad overlap meaning. Use schedule for exact attendance/windows.","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Success envelope with data.sessions, total, unfilteredTotal, page, pageCount, limit, orderBy, order, columns, tier and sourceClass. total is the matched root count before pagination; includeRows=false leaves the array empty.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"const":true},"data":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/CanonicalDetailRow"}},"total":{"type":"integer","minimum":0},"unfilteredTotal":{"type":"integer","minimum":0},"page":{"type":"integer","minimum":1},"pageCount":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1},"orderBy":{"type":"string"},"order":{"type":"string","enum":["asc","desc"]},"columns":{"type":"array","items":{"type":"string"}},"tier":{"type":"string"},"sourceClass":{"const":"canonical"}},"required":["sessions","total","unfilteredTotal","page","pageCount","limit","orderBy","order","columns","tier","sourceClass"]}},"required":["success","data"]}}}},"400":{"description":"Invalid search, score bound, relationship ID, or structured filter; malformed/repeated filter JSON or a limit exceeded."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"403":{"description":"A filter field or relationship is unavailable under current field disclosure."},"500":{"$ref":"#/components/responses/ServerError"}},"x-curl-examples":[{"title":"Find sessions under a typed filter","code":"curl --get \"https://apis.schoolsoutapp.com/api/sessions\" -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" --data-urlencode 'filter={\"field\":\"age_range_years\",\"op\":\"contains\",\"value\":10}'"}]}},"/api/activities/facets":{"get":{"description":"Counts under the canonical list filters and current field access. A single-field request with snapshot=true and no search or filters reads durable incrementally maintained counts after relevant background work settles. While committed edits, deletion, blacklisting, or calendar expiry work is pending, the request falls back to live counts; failed refreshes leave that fallback active. Filtered requests and the default stay live. The same structured filter JSON and legacy list filters narrow the population using AND before aggregation. Structured filters always use live counts. q searches facet values; search carries the list text search. All filter branches enforce current field disclosure.","parameters":[{"description":"Facet field; required when snapshot=true.","in":"query","name":"field","schema":{"type":"string"}},{"description":"Use the stored unfiltered chart distribution. Must be exactly true or false.","in":"query","name":"snapshot","schema":{"default":false,"type":"boolean"}},{"in":"query","name":"limit","schema":{"default":30,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Filter records before aggregation; uses live counts.","in":"query","name":"search","schema":{"type":"string"}},{"description":"Search facet values; uses live counts.","in":"query","name":"q","schema":{"type":"string"}},{"description":"Case-insensitive exact city name or its lowercase hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Case-insensitive exact region, such as a state abbreviation.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on this activity; no parent inheritance.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Returns records whose stated grade range includes this grade. Use -1 for pre-K and 0 for kindergarten.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON predicate tree, sent once. Combines with all legacy filters using AND before rows, totals and facet counts are selected. Read /api/canonical/schema tables[*].filterCapabilities for visible fields, operators, relations and limits. Invalid/unknown/over-complex filters return 400; unavailable fields return 403, including in nonmatching branches. Do not broaden a failed request by dropping predicates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"organizationId","in":"query","required":false,"description":"Exact organization UUID. Selects the activity own organization.","schema":{"type":"string","format":"uuid"}},{"name":"skillLevel","in":"query","required":false,"description":"Exact recorded skill_level value.","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"Exact recorded format value.","schema":{"type":"string"}},{"name":"seasonality","in":"query","required":false,"description":"Exact recorded seasonality value.","schema":{"type":"string"}}],"responses":{"200":{"description":"Existing success envelope containing facets, tier, resultLimit, and sourceClass. A single field returns values with value, label, and rows."},"400":{"description":"Invalid field or snapshot option. Also returned for malformed, repeated, unknown, over-complex or incorrectly typed structured filter JSON."},"401":{"description":"Authentication required."},"402":{"description":"Starter or higher required."},"403":{"description":"A structured filter names a field or relationship outside current tier or preview disclosure."}},"summary":"Read activities facet or chart counts","tags":["Canonical"],"x-auth":"Account or named integration API key on Starter or above. Facet fields follow the owner’s current plan.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/activities/facets\" -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" --data-urlencode \"field=category\" --data-urlencode \"snapshot=true\"","title":"Read activities chart counts"}]}},"/api/activities/{id}":{"get":{"description":"Returns the tier-masked activity and related summaries. Activities have no enrollment price, currency, discount, or care-pricing fields. Session care quotes follow price access rules. Its image_url compatibility read returns the selected active cover only. Pricing remains tier-masked, including nested schedule quotes. Normal JSON records omit bookkeeping and ingestion history, null and blank record fields, and unknown availability, registration-status, and coordinate-precision values. Zero, false, empty arrays, masked values, positional range bounds, and structured schedule states retain their meanings. Related entity summaries follow the same projection; CSV and SQL retain their existing contracts. Moved fields are configuration_id, external_ids, created_at, updated_at, source_created_at, field_provenance, source_records, merge_jobs, and relationship_jobs. Read permitted bookkeeping and provenance at /api/activities/{id}/provenance. Age ranges use age_range_years; normal JSON records and column metadata omit the redundant age_range_months alias. CSV, SQL, and the legacy ageMonths filter retain month compatibility. Records and column metadata omit score. Read /api/activities/{id}/score for live detail or /api/activities/scores?ids=UUID,UUID&cached=true for persisted summaries. Normal detail responses include data.media, the first gallery page of up to 100 images, with entity, items, coverId, logoId, total, limit, and offset. Images include displayUrl, label, kind, width, and height; source attribution is omitted even for ADMIN. Previews omit media. Optional includeMedia=false skips the gallery; omitted or true includes it. The parameter accepts one exact true or false value, with malformed or repeated values returning 400. Use the existing /media endpoint for additional pages or authorized source attribution. On /media, includeProvenance=false skips source attribution; omitted or true retains existing authority-gated sources. Use limit=1 at the selected image offset when requesting only its source history. The record's independent overnight boolean is true for explicit overnight status and false for explicit day status; unknown or mixed status is omitted. It never inherits a parent's status. Ordinary permitted JSON records include resolved_cover with the ultimate source entity, inheritance flag, and structured stock attribution. Owned gallery and image compatibility fields retain their existing meaning.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"name":"includeMedia","in":"query","required":false,"description":"One exact true or false value. Omitted or true bundles the first gallery page; false skips media for follow-up diagnostic reads. Previews always omit media.","schema":{"type":"boolean","default":true}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"activity":{"$ref":"#/components/schemas/CanonicalDetailRow"},"media":{"$ref":"#/components/schemas/CanonicalMediaPage"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Canonical activity detail"},"404":{"$ref":"#/components/responses/NotFound"},"400":{"description":"Invalid detail parameters, including malformed or repeated includeMedia."}},"summary":"Read one canonical activity","tags":["Organization catalog"],"x-auth":"Account cookie or header, or permitted machine key, from Starter up.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/activities/$ACTIVITY_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read one activity"}]}},"/api/activities/{id}/media":{"get":{"description":"Returns this record’s owned paginated gallery and selections plus resolvedCover for display. Inherited covers retain their owning record and do not change gallery membership or counts. Stock covers include public provider and photographer credits. Remote URLs and R2 URLs are served directly; uploaded assets retain protected URLs. Source evidence is available only to non-preview ADMIN accounts. Pagination uses the existing catalog bounds.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Defaults to 30 when absent or invalid; values over 100 cap at 100.","in":"query","name":"limit","schema":{"default":30,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Defaults to 0 when absent or invalid; values over 1000000 cap at 1000000.","in":"query","name":"offset","schema":{"default":0,"maximum":1000000,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/CanonicalMediaPage"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Paginated media and selected IDs"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Starter access is required."},"403":{"description":"Previews cannot read media."},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Read activity media","tags":["Organization catalog"],"x-auth":"Starter or above; previews are denied. Resolved covers follow the same media access gates.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/activities/$ACTIVITY_ID/media\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"limit=30\" \\\n  --data-urlencode \"offset=0\"","title":"Read the first page of an activity gallery"}]}},"/api/assistant":{"post":{"description":"Assistant answers in short conversational replies using the same tier-filtered read-only canonical database access as Ask. Greetings, acknowledgments, clarification, and general planning need no query and can have empty results, sources, and limitations. After a query is attempted, the answer must cite usable evidence or explain the data limitation. Listing facts still require current-turn evidence. Optional browser history (at most 16 exchanges, 24,000 characters and 10 result references each) is untrusted and not stored. Alternatively, conversation {requestId, id?} saves this turn in an account-owned conversation and uses its stored completed turns as history; history and conversation cannot be combined. A repeated requestId returns the stored answer as {replayed:true, credits:null} without generating or charging; a pending or failed requestId returns 409, and only one turn per conversation can be pending. includeFamilyContext:true adds the viewer's GET /api/users/viewer/family-context projection as saved data. Family context and saved conversations use the family policy and refuse service delegation. Charges the existing Ask allowance; generation failures refund it and settle a saved turn as failed or cancelled. Streams NDJSON statuses and a terminal result with data.response and data.credits (and data.saved for saved turns); every event of a saved turn carries conversation {id, turnId}. Each result references an activity or session identifier from a returned row, with that row as record and the price, age, location, date, or time facts it left empty (missing) or did not select (unchecked). Assistant never saves family information. Disconnect cancels unfinished generation. Result assessments reuse returned organization freshness/confidence and source dates, preserve activity/session fact scope, and expose missing or unselected price, age, hours and availability facts. Organization scores do not verify specific facts. Price periods, mandatory fees and current places remain unconfirmed without supporting evidence. Ambiguous rows and known unsupported verification-recency wording share one bounded correction attempt with explicit uncertainty on repeated failure. Responses may include up to three preferenceProposals for parent review: budget, search_area, child_interests, memory_fact (a statement, category and optional permitted childId for a lasting family fact), or search_recap. Each quote is an exact current-question substring, not listing/history evidence; invalid proposals are discarded. Unknown dimensions are null and must be completed during review. Legacy responses may omit preferenceProposals. A proposal neither saves nor approves anything. After explicit review, the parent uses the existing versioned household or child PATCH endpoint with the actual completed turn source. A reviewed memory_fact is saved with POST /api/users/viewer/family-memory, approve:true and that same source. Saving requires saved:true, replayed:true, or a completed turn returned by the conversation API; saved:false is not a completed source. Reload after conflicts or uncertain saves; do not retry against a new version without review. With webSearch:true, the catalog still comes first: web search is offered to the model only after a returned listing shows a selected fact with no value or stale organization evidence, or after it tried to finish without a catalog result (a single empty query is widened once first). The model never writes the search text: the server builds it from fixed fields, refuses a child's label and any word from saved requirements, notes or remembered facts the parent did not type in this conversation, screens a query that goes beyond the parent's own words for health, support or family circumstances, and runs it in a separate provider request that sees nothing else. Web pages appear in sources as {evidenceId: web-N, sourceClass: web, url, title, providerSite}; only pages a search retrieved in that turn are listed, and everything they say is advertised, not confirmed. Clients that validate sources must accept the web class before sending webSearch:true. Without it, answers and sources are unchanged. A search_recap proposal records which shown options the parent chose or ruled out, with server-supplied names and a ready memoryFact for the parent to approve; options are nameable only from this answer's results or a saved conversation.","requestBody":{"content":{"application/json":{"schema":{"properties":{"conversation":{"additionalProperties":false,"properties":{"id":{"description":"Continue this conversation; omit to start one.","format":"uuid","type":"string"},"requestId":{"description":"Client-generated idempotency key for this turn.","pattern":"^[A-Za-z0-9_-]{8,64}$","type":"string"}},"required":["requestId"],"type":"object"},"history":{"description":"Earlier exchanges in the current conversation, oldest first. Unknown fields are refused.","items":{"additionalProperties":false,"properties":{"answer":{"maxLength":6000,"minLength":1,"type":"string"},"question":{"maxLength":5000,"minLength":1,"type":"string"},"results":{"description":"Results that answer showed, in order, so a later reply such as \"the second one\" can refer to them.","items":{"additionalProperties":false,"properties":{"id":{"format":"uuid","type":"string"},"kind":{"enum":["activity","session"]}},"required":["kind","id"],"type":"object"},"maxItems":10,"type":"array"}},"required":["question","answer"],"type":"object"},"maxItems":16,"type":"array"},"includeFamilyContext":{"default":false,"description":"Add the viewer's approved family context as saved data, never instructions.","type":"boolean"},"question":{"maxLength":5000,"minLength":1,"type":"string"},"webSearch":{"default":false,"description":"Allow a web search fallback after the catalog has been tried. Answers may then include sources with sourceClass web.","type":"boolean"}},"required":["question"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/x-ndjson":{"schema":{"oneOf":[{"properties":{"status":{"properties":{"detail":{"type":"string"},"phase":{"type":"string"},"title":{"type":"string"}},"required":["phase","title"],"type":"object"},"type":{"const":"status"}},"required":["type","status"],"type":"object"},{"properties":{"data":{"properties":{"credits":{"properties":{"allotment":{"type":["integer","null"]},"balance":{"type":["integer","null"]},"charged":{"type":"integer"},"lifetime":{"type":"boolean"},"pooled":{"type":"boolean"},"unlimited":{"type":"boolean"}},"type":"object"},"response":{"additionalProperties":false,"properties":{"agent":{"const":"Assistant"},"answer":{"type":"string"},"limitations":{"items":{"type":"string"},"type":"array"},"preferenceProposals":{"description":"Optional for historical responses; new answers return an array. Quotes are exact current-question substrings, capped at 500 characters. Budget amounts have at most two decimal places. Non-null child IDs must occur in the supplied permitted family context. Parent review remains required; quotation does not certify the interpretation.","items":{"anyOf":[{"additionalProperties":false,"properties":{"budget":{"additionalProperties":false,"properties":{"amount":{"maximum":1000000,"minimum":0,"type":["number","null"]},"currency":{"pattern":"^[A-Z]{3}$","type":["string","null"]},"limit":{"enum":["hard_cap","preference",null],"type":["string","null"]},"period":{"enum":["day","week","month","session","season","year","total",null],"type":["string","null"]},"scope":{"enum":["per_child","household",null],"type":["string","null"]}},"required":["amount","currency","period","scope","limit"],"type":"object"},"kind":{"enum":["budget"],"type":"string"},"quote":{"maxLength":500,"minLength":1,"type":"string"}},"required":["kind","quote","budget"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"enum":["search_area"],"type":"string"},"quote":{"maxLength":500,"minLength":1,"type":"string"},"searchArea":{"additionalProperties":false,"properties":{"label":{"maxLength":120,"minLength":1,"type":"string"},"postalCode":{"pattern":"^[0-9]{5}$","type":["string","null"]},"region":{"pattern":"^[A-Z]{2}$","type":["string","null"]}},"required":["label","region","postalCode"],"type":"object"}},"required":["kind","quote","searchArea"],"type":"object"},{"additionalProperties":false,"properties":{"childId":{"pattern":"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","type":["string","null"]},"interests":{"items":{"maxLength":100,"minLength":1,"type":"string"},"maxItems":20,"minItems":1,"type":"array"},"kind":{"enum":["child_interests"],"type":"string"},"quote":{"maxLength":500,"minLength":1,"type":"string"}},"required":["kind","quote","childId","interests"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"enum":["memory_fact"],"type":"string"},"memoryFact":{"additionalProperties":false,"properties":{"category":{"enum":["activity_history","logistics","preference","other"],"type":"string"},"childId":{"pattern":"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","type":["string","null"]},"statement":{"maxLength":500,"minLength":1,"type":"string"}},"required":["statement","category","childId"],"type":"object"},"quote":{"maxLength":500,"minLength":1,"type":"string"}},"required":["kind","quote","memoryFact"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"enum":["search_recap"],"type":"string"},"memoryFact":{"additionalProperties":false,"description":"The record the server wrote from the named options, ready for the parent to approve through the family-memory route.","properties":{"category":{"enum":["activity_history","logistics","preference","other"],"type":"string"},"childId":{"pattern":"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","type":["string","null"]},"statement":{"maxLength":500,"minLength":1,"type":"string"}},"required":["statement","category","childId"],"type":"object"},"quote":{"maxLength":500,"minLength":1,"type":"string"},"searchRecap":{"additionalProperties":false,"properties":{"chosen":{"items":{"additionalProperties":false,"properties":{"id":{"pattern":"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","type":"string"},"kind":{"enum":["activity","session"],"type":"string"},"name":{"description":"The listing's name from the row the viewer was shown.","maxLength":60,"type":"string"}},"required":["kind","id","name"],"type":"object"},"maxItems":3,"type":"array"},"ruledOut":{"items":{"additionalProperties":false,"properties":{"id":{"pattern":"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","type":"string"},"kind":{"enum":["activity","session"],"type":"string"},"name":{"description":"The listing's name from the row the viewer was shown.","maxLength":60,"type":"string"},"reason":{"description":"The parent's stated reason, when given.","maxLength":80,"type":"string"}},"required":["kind","id","name"],"type":"object"},"maxItems":5,"type":"array"},"summary":{"maxLength":150,"minLength":1,"type":"string"}},"required":["summary","chosen","ruledOut"],"type":"object"}},"required":["kind","quote","searchRecap","memoryFact"],"type":"object"}]},"maxItems":3,"type":"array"},"question":{"type":"string"},"results":{"items":{"additionalProperties":false,"properties":{"assessment":{"$ref":"#/components/schemas/AssistantEvidenceAssessment"},"evidenceId":{"type":"string"},"id":{"format":"uuid","type":"string"},"kind":{"enum":["activity","session"]},"missing":{"items":{"enum":["price","ages","location","dates","times"]},"type":"array"},"record":{"description":"The viewer's returned row for this result.","type":"object"},"unchecked":{"items":{"enum":["price","ages","location","dates","times"]},"type":"array"}},"required":["kind","id","evidenceId","record","missing","unchecked","assessment"],"type":"object"},"maxItems":10,"type":"array"},"sources":{"items":{"oneOf":[{"additionalProperties":false,"properties":{"evidenceId":{"type":"string"},"fields":{"items":{"type":"string"},"type":"array"},"rows":{"minimum":0,"type":"integer"},"sourceClass":{"const":"canonical"}},"required":["evidenceId","sourceClass","fields","rows"],"type":"object"},{"additionalProperties":false,"properties":{"evidenceId":{"pattern":"^web-[1-9][0-9]*$","type":"string"},"providerSite":{"description":"Whether the page is on the activity provider's own website.","type":"boolean"},"sourceClass":{"const":"web"},"title":{"description":"Untrusted page title for display.","maxLength":200,"type":"string"},"url":{"description":"A page the web search retrieved in this turn.","format":"uri","type":"string"}},"required":["evidenceId","sourceClass","url","title","providerSite"],"type":"object"}]},"type":"array"},"suggestedReplies":{"description":"Short replies to the answer's final question, shown as buttons; the parent may still type freely.","items":{"maxLength":120,"minLength":1,"type":"string"},"maxItems":4,"type":"array"}},"required":["agent","question","answer","suggestedReplies","results","sources","limitations"],"type":"object"}},"required":["response","credits"],"type":"object"},"success":{"const":true},"type":{"const":"result"}},"required":["type","success","data"],"type":"object"},{"properties":{"data":{"type":"null"},"error":{"const":true},"message":{"type":"string"},"type":{"const":"error"}},"required":["type","error","message","data"],"type":"object"}]}}},"description":"Newline-delimited JSON status events followed by one result or error event."},"400":{"description":"Missing, invalid, or oversized question."},"401":{"description":"Authentication required."},"402":{"description":"The account Ask allowance is unavailable or exhausted."},"403":{"description":"Not a staff or ADMIN account, origin or CSRF denied, or a machine key or preview session. Returned before any allowance check or generation."},"413":{"description":"Request body exceeds 32 KiB."},"429":{"description":"Account request allowance exceeded."},"502":{"description":"Account allowance could not be confirmed."},"503":{"description":"Agent configuration or canonical scoring readiness unavailable."}},"security":[{"AccountCredential":[]}],"summary":"Ask Assistant a question using read-only canonical data","tags":["Internal assistant"],"x-auth":"Staff or ADMIN account only during internal testing, decided from the stored account. Current account credential or signed Intelligence session with CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Service delegation to a staff or ADMIN account is allowed only without includeFamilyContext or conversation. Machine keys and investor-preview sessions are refused.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/assistant\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"question\":\"Only afternoons\",\"includeFamilyContext\":true,\"conversation\":{\"id\":\"$CONVERSATION_ID\",\"requestId\":\"turn-0002\"}}'","title":"Continue a saved conversation with family context"}],"x-internal":true}},"/api/assistant/conversations":{"get":{"description":"Returns up to 200 of the account's conversations, most recently updated first, without turns. Conversations are kept until deleted or the account is deleted.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"conversations":{"items":{"properties":{"createdAt":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"title":{"type":"string"},"turns":{"items":{"properties":{"createdAt":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"position":{"type":"integer"},"question":{"type":"string"},"requestId":{"type":"string"},"response":{"type":["object","null"]},"settledAt":{"format":"date-time","type":["string","null"]},"status":{"enum":["pending","completed","failed","cancelled"]}},"required":["id","position","requestId","status","question","response","createdAt","settledAt"],"type":"object"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","title","createdAt","updatedAt"],"type":"object"},"type":"array"}},"required":["conversations"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"401":{"description":"Current account required"},"403":{"description":"Not the viewer's own account session or credential"}},"security":[{"AccountCredential":[]}],"summary":"List saved Assistant conversations","tags":["Internal assistant"],"x-auth":"Current account cookie or account credential only; delegated service requests, machine keys and investor previews are refused. Conversations are private to their owner. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/assistant/conversations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List saved conversations"}],"x-internal":true}},"/api/assistant/conversations/{conversationId}":{"delete":{"description":"Permanently deletes the transcript and its turns and clears references to it from profile, household and care provenance and from remembered facts. Facts and values the parent approved remain because their approval is independent.","parameters":[{"in":"path","name":"conversationId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"deleted":{"const":true}},"required":["deleted"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"403":{"description":"Not the viewer's own account session or credential"},"404":{"description":"Record not found for this account"}},"security":[{"AccountCredential":[]}],"summary":"Delete a saved Assistant conversation","tags":["Internal assistant"],"x-auth":"Current account cookie or account credential only; delegated service requests, machine keys and investor previews are refused. Conversations are private to their owner. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/assistant/conversations/$CONVERSATION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Delete a saved conversation"}],"x-internal":true},"get":{"description":"Returns every turn in order with its status. Only completed turns store an answer; failed and cancelled turns keep the accepted question. A pending turn older than five minutes is settled as failed by the next request in that conversation.","parameters":[{"in":"path","name":"conversationId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"conversation":{"properties":{"createdAt":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"title":{"type":"string"},"turns":{"items":{"properties":{"createdAt":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"position":{"type":"integer"},"question":{"type":"string"},"requestId":{"type":"string"},"response":{"type":["object","null"]},"settledAt":{"format":"date-time","type":["string","null"]},"status":{"enum":["pending","completed","failed","cancelled"]}},"required":["id","position","requestId","status","question","response","createdAt","settledAt"],"type":"object"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"}},"required":["id","title","createdAt","updatedAt"],"type":"object"}},"required":["conversation"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"403":{"description":"Not the viewer's own account session or credential"},"404":{"description":"Record not found for this account"}},"security":[{"AccountCredential":[]}],"summary":"Read a saved Assistant conversation","tags":["Internal assistant"],"x-auth":"Current account cookie or account credential only; delegated service requests, machine keys and investor previews are refused. Conversations are private to their owner. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/assistant/conversations/$CONVERSATION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read a saved conversation"}],"x-internal":true}},"/api/auth/gmail-callback":{"get":{"description":"Consumes the Google state and requires the starting browser nonce. Web flow exchanges the code, validates both Gmail scopes and stores the sealed grant, then returns gmail=connected, denied or failed. Native flow only seals a short-lived authorization code and returns gmail=authorized&code=<one-use completion>; denial/failure includes no code. Only authenticated app completion may exchange and save a native grant. Every valid-state native outcome echoes challenge=<original public S256>; the app must match it to its pending attempt before completing or clearing its proof.","parameters":[{"description":"One-time browser state, checked against its nonce cookie.","in":"query","name":"state","required":true,"schema":{"type":"string"}},{"description":"Google authorization code; never forwarded to the app in plaintext.","in":"query","name":"code","required":false,"schema":{"type":"string"}},{"description":"Google denial indicator; raw provider error text is not forwarded.","in":"query","name":"error","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"Allowed parent page or app callback with a bounded outcome and optional one-use native completion ticket."},"400":{"description":"Invalid, expired or reused flow, missing proof, or rejected Google grant."}},"security":[],"summary":"Return from Google Gmail consent","tags":["Internal Gmail"],"x-auth":"This endpoint is open to the public (Google redirect target); the one-time state and the starting browser's nonce cookie identify the parent","x-curl-examples":[{"code":"curl -i -X GET \"https://apis.schoolsoutapp.com/api/auth/gmail-callback?state=$STATE&code=$GOOGLE_CODE\" \\\n  -H \"Cookie: $GMAIL_NONCE_COOKIE\"","title":"Return from Google consent"}],"x-internal":true}},"/api/auth/gmail-start":{"get":{"description":"Consumes ticket, sets the HttpOnly callback nonce in the system browser, then redirects to Google consent. Expired or replayed tickets return 400. No account credential is accepted in a URL; the browser step alone cannot store a connection.","parameters":[{"description":"One-time native bootstrap ticket.","in":"query","name":"ticket","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"302":{"description":"Google consent redirect with the browser nonce cookie; no-store and no-referrer."},"400":{"description":"Invalid, expired or reused flow, missing proof, or rejected Google grant."}},"security":[],"summary":"Open native Gmail consent in its authentication browser","tags":["Internal Gmail"],"x-auth":"Public, independent-auth browser navigation. A one-use 10-minute native bootstrap ticket identifies the starting account and app proof.","x-curl-examples":[{"code":"curl -i -X GET \"https://apis.schoolsoutapp.com/api/auth/gmail-start?ticket=$TICKET\"","title":"Open the native bootstrap redirect"}],"x-internal":true}},"/api/canonical/map":{"get":{"description":"Accessible coordinates retain full stored precision on every plan; preview field masks apply before viewport membership and grouping. Stable world-anchored cells intersecting the requested viewport are returned in full, including records just outside its edges. Grid resolution coarsens to a bounded feature budget without sampling. coverage reports the full matching permitted population, while viewport reports complete displayed cells. Counts are records, not distinct camps. Each entity retains its own configuration; child venues never inherit headquarters. Approximate source coordinates remain separate from address-grade points. Selected-region membership uses distance in meters from the viewer-masked stored point to the unsimplified boundary, with inclusive layer tolerances initially 100 m for neighborhoods, 500 m for cities/ZIPs, 2 km for counties, 5 km for metros, and 10 km for states. A point-centered tolerance circle may partially overlap the region; the center need not be inside, and records may match multiple regions. The same rule applies to address-grade and ZIP/state approximate points, without source-area polygon intersections or zoom dependence. Unknown, missing, masked, and invalid locations are excluded. Approximate quality remains separate. This does not change structured canonical/Ask location classifications. Optional includeCampPoints=true adds an organization-only campPoints GeoJSON collection from the same masked cohort and snapshot. Only exact/building/parcel/street precision is included, within the requested projected-coordinate bbox including its edges. Organization IDs remain distinct at shared coordinates; properties are empty by default. Optional includeCampNames=true additionally adds properties.name only when the camp name is disclosed, using the existing viewer-level text scrubbing and preview name masks. It requires includeCampPoints=true or returns HTTP 400. Omitted/false adds no name property and performs no camp-point name reads. Hidden or missing names have no fallback label. Names share each camp point's masked coordinate, filtered cohort, and snapshot; groups never supply camp labels. The frontend requests this projection only at label zoom and uses collision-managed native symbols. Additional includeCampScores=true adds properties.scoreBand from the persisted organization score and requires includeCampPoints=true or returns HTTP 400. Bands are weak, fair, good, strong, or unavailable and use the same thresholds as organization score details. Missing prepared scores, restricted accounts, and every preview receive unavailable. Omitted/false skips score-band reads. Workers own score calculation and refresh; map reads do not calculate scores. Approximate ZIP/state points and child records are excluded. Overflow rejects the request with HTTP 413 rather than truncating points; omitted or false preserves the existing response. Map and member reads exclude identities with committed source work still queued and overlay those identities from current source rows. Projection state and the live overlay share one repeatable-read snapshot; a proven clean snapshot takes the saved-row fast path. Initial preparation returns HTTP 503 with code=map_cache_warming; callers may retry this state. Successes optionally use application/vnd.schoolsout.map+cbor;version=1 when explicitly requested with Accept at positive quality at least as high as JSON. JSON remains the default; errors before a stream starts remain JSON. The data model and authorization are unchanged; responses vary on Accept and Accept-Encoding and retain private, no-store. Successful finished responses may be reused from a bounded per-process memory cache keyed by normalized options, current disclosure policy, stream version, representation, and compression. PostgreSQL retains validity fences and invalidation history, not response bodies; completed responses do not survive process restarts. Every request still authenticates and checks access. Source, live eligibility, score, geography, and projection changes invalidate dependent responses; reuse expires by its maximum age and the next UTC midnight. Cache failures fall back to normal reads. Private/no-store and JSON error behavior remain unchanged. X-Map-Revision, when available, is an opaque equality token scoped to relevant source changes, disclosure, policy, and UTC day; clients must not parse it. Successful responses carry a weak ETag bound to normalized options, disclosure, representation, and compression. Send it with If-None-Match to revalidate; after current authorization and a fresh source-fence check, a match returns HTTP 304 with no body and without running the map data query. Retain a streamed ETag only after its complete frame passes sequence and count validation. Revision tokens fence server response reuse and remain available to clients; metadata revision changes do not automatically replace an already loaded Explorer point snapshot. Score writes invalidate requests with minimumScore or maximumScore filters and requests with includeCampScores=true. The map route additionally accepts application/vnd.schoolsout.map-stream+cbor;version=1. After optional whole-stream gzip decompression, each frame is a four-byte unsigned big-endian payload length followed by one CBOR object, capped at 1 MiB. Frames have type: start (version 1, bounds [west,south,east,north], opaque revision or empty string when unavailable), zero or more points (zero-based sequence, features), result (data contains ordinary map metadata without campPoints), and complete (pointCount, batchCount). Gzip flushes per frame. Points are provisional until complete and matching totals; terminal error frames contain code and message. Abort, overflow, malformed/truncated streams, invalid sequences, and missing completion cannot establish reusable coverage or cached success. Pre-stream errors retain JSON status/error responses. Completed streams may be cached as their own representation. Explorer requests all permitted, plottable camp dots in one world-bounds stream for the current filters/access, with names up front. It retains the completed cohort snapshot until filters/access change, explicit refresh, or reload. Pan and zoom request separate camera-specific counts/groups without downloading points again; metadata revision changes do not automatically refresh the dots. Camp dots open camp information directly at every zoom. Use bounded ordinary JSON/CBOR fallback when streaming is unsupported. Progressive delivery targets earlier points without a fixed latency guarantee. The route also supports application/vnd.schoolsout.map-stream+cbor;version=2 when includeCampPoints=true; omitted or false returns HTTP 400 before streaming. V2 uses the same uint32 big-endian length-prefixed CBOR framing, whole-stream gzip, 1 MiB frame limit, provisional points, terminal errors, and completion checks as v1. Its start frame contains version 2, bounds, opaque revision, and ordered columns: id, longitude, latitude, followed by name when includeCampNames=true and scoreBand when includeCampScores=true. Points frames contain zero-based sequence and positional rows matching those columns; coordinates remain float64 and an included missing or undisclosed name is null. Complete contains matching pointCount and batchCount. V2 has no features or result frame and does not calculate grouping, coverage, viewport, tier, region, or preview metadata. Selected-region validation still returns pre-stream HTTP 400 for a missing boundary or dataset, or a dataset that is not active; it never substitutes an empty successful point population. Accept quality chooses v1 or v2. Each API instance warms completed-response bytes independently, so a restart begins cold. Every reuse validates the current database snapshot, compaction epoch, scoped dependency revision, and UTC evaluation day. Durable canonical map and boundary materialized projections remain in PostgreSQL across restarts. Migration 0047 adds GiST indexes on the guarded WGS84 geography expressions used by selected-region reads from canonical_map_records and entity_configurations. They narrow candidate identities; the query materializes distinct float8 longitude/latitude pairs, evaluates authoritative ST_DWithin once per pair, then joins matches back to every identity. Float8 is the existing ST_MakePoint input conversion, not new rounding. Stored source coordinates, output precision, masking, preview disclosure, boundary geometry, tolerances, and exact membership identities remain unchanged. Prepare migration 0047 before deploying the matching API code. ageYears uses whole completed years. The legacy ageMonths filter remains available; month-shaped aliases derived from canonical inclusive year bounds use [yearMin*12,yearMax*12+11]. collectionId is staff-only; collections contain organizations and do not infer activity or session category labels. Structured filter JSON uses filterKind=organization (default), activity, or session. Matching children select their effectively owning camps, with direct session organization before activity fallback. The cohort includes those camps and all disclosed effectively owned activities/sessions, including children that did not match the tree, before existing legacy filters and per-record geography narrow it using AND. Camp dots use the camp own coordinates. Preserve both parameters across snapshots, viewport reads, members and summaries. Original tree limits, fixed preview disclosure and field permissions apply; the internal camp projection consumes no extra predicate budget. This selection is identical across JSON, CBOR, finite v1/v2 and live SSE transports; global text-search suggestions stay separate.","parameters":[{"description":"West,south,east,north in longitude/latitude degrees. West greater than east crosses the antimeridian.","in":"query","name":"bbox","required":true,"schema":{"example":"-125,24,-66,50","type":"string"}},{"description":"Map zoom used to choose bounded display detail.","in":"query","name":"zoom","required":true,"schema":{"maximum":22,"minimum":0,"type":"number"}},{"description":"Include precise organization points within the requested bounds. Uses the same cohort, selected region, masking, and preview disclosure; rejects overflow rather than sampling.","in":"query","name":"includeCampPoints","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Add disclosed names to campPoints using the existing viewer-level text scrubbing and preview masks. Requires includeCampPoints=true. Hidden/missing names are omitted; omitted/false skips name reads.","in":"query","name":"includeCampNames","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Add persisted organization score bands to campPoints. Requires includeCampPoints=true. Missing prepared scores, restricted accounts, and every preview receive unavailable; omitted/false skips score-band reads.","in":"query","name":"includeCampScores","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Case-insensitive search in each entity kind using its permitted canonical search fields.","explode":true,"in":"query","name":"q","required":false,"schema":{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Each record’s own city, case-insensitive exact name or hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Each record’s own recorded region; distinct from the selected polygon.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on each matching record; categories are independent across organizations, activities, and sessions.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Matches the record’s own stated inclusive configuration range.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Organization identity or child lineage.","in":"query","name":"organizationId","required":false,"schema":{"type":"string"}},{"description":"Activity identity or matching ancestor/descendant activity.","in":"query","name":"activityId","required":false,"schema":{"type":"string"}},{"description":"Matching activity skill level.","in":"query","name":"skillLevel","required":false,"schema":{"type":"string"}},{"description":"Matching activity format.","in":"query","name":"format","required":false,"schema":{"type":"string"}},{"description":"Matching activity seasonality.","in":"query","name":"seasonality","required":false,"schema":{"type":"string"}},{"description":"Matching session registration status; its field access gate applies.","in":"query","name":"registrationStatus","required":false,"schema":{"type":"string"}},{"description":"Matching sessions ending on or after this date.","in":"query","name":"from","required":false,"schema":{"type":"string"}},{"description":"Matching sessions starting on or before this date.","in":"query","name":"to","required":false,"schema":{"type":"string"}},{"description":"Selected source boundary kind; requires regionCode and regionDataset.","in":"query","name":"regionKind","required":false,"schema":{"enum":["state","zip","metro","county","city","neighborhood"],"type":"string"}},{"description":"Stable source identifier for the selected boundary.","in":"query","name":"regionCode","required":false,"schema":{"type":"string"}},{"description":"Immutable imported dataset ID. Retired installed datasets remain selectable.","in":"query","name":"regionDataset","required":false,"schema":{"type":"string"}},{"description":"Revalidate a completed response using its ETag. Current authorization and source dependencies are checked before an unchanged response returns 304.","in":"header","name":"If-None-Match","required":false,"schema":{"type":"string"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Requires a direct staff or ADMIN account; service delegation, machine keys, and previews are refused. Filters organizations by one shared camp collection; map routes include coherently owned descendants.","in":"query","name":"collectionId","required":false,"schema":{"format":"uuid","type":"string"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON CanonicalFilter tree, sent once and evaluated against filterKind (organization by default). A matching activity/session selects its effectively owning camp; a session direct organization wins before activity fallback. The resulting cohort includes selected camps and all their disclosed effectively owned children, including nonmatching children, before legacy filters and geography narrow it using AND. Camp dots use each camp own coordinates. Original tree limits and current field/preview disclosure apply; the internal camp projection consumes no extra depth or byte budget. Send the same filter and filterKind on map points, metadata, members and summary reads.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"filterKind","in":"query","required":false,"description":"Root entity type for filter. Requires filter and appears once. Organization roots select matching camps; activity/session roots select camps owning matching children. This does not limit mixed metadata, members or summary counts to matching children. Every camp dot retains its own address-grade location.","schema":{"type":"string","enum":["organization","activity","session"],"default":"organization"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"campPoints":{"description":"Present only when includeCampPoints=true. Organization-only points within the exact requested projected-coordinate bounds; excludes approximate locations and children.","properties":{"features":{"items":{"properties":{"geometry":{"properties":{"coordinates":{"items":{"type":"number"},"maxItems":2,"minItems":2,"type":"array"},"type":{"const":"Point"}},"required":["type","coordinates"],"type":"object"},"id":{"description":"Organization UUID; distinct organizations retain distinct IDs at a shared coordinate.","format":"uuid","type":"string"},"properties":{"additionalProperties":false,"properties":{"name":{"description":"Present only when includeCampNames=true and the camp name is disclosed. Existing viewer-level text scrubbing and preview name masks apply; missing/hidden names are omitted without an identifier fallback.","type":"string"},"scoreBand":{"description":"Present only when includeCampScores=true. Uses the persisted organization score and the same bands as score details. Missing prepared scores, restricted accounts, and every preview receive unavailable.","enum":["weak","fair","good","strong","unavailable"],"type":"string"}},"type":"object"},"type":{"const":"Feature"}},"required":["type","id","geometry","properties"],"type":"object"},"maxItems":100000,"type":"array"},"type":{"const":"FeatureCollection"}},"required":["type","features"],"type":"object"},"coverage":{"properties":{"approximate":{"minimum":0,"type":"integer"},"byKind":{"additionalProperties":{"properties":{"approximate":{"minimum":0,"type":"integer"},"exact":{"minimum":0,"type":"integer"},"located":{"minimum":0,"type":"integer"},"total":{"minimum":0,"type":"integer"},"unlocated":{"minimum":0,"type":"integer"}},"required":["total","located","exact","approximate","unlocated"],"type":"object"},"type":"object"},"exact":{"minimum":0,"type":"integer"},"located":{"minimum":0,"type":"integer"},"total":{"minimum":0,"type":"integer"},"unlocated":{"minimum":0,"type":"integer"}},"type":"object"},"features":{"items":{"properties":{"geometry":{"properties":{"coordinates":{"items":{"type":"number"},"maxItems":2,"minItems":2,"type":"array"},"type":{"const":"Point"}},"type":"object"},"id":{"type":"string"},"properties":{"properties":{"approximate":{"type":"integer"},"coordinatePrecision":{"$ref":"#/components/schemas/CoordinatePrecision"},"count":{"minimum":1,"type":"integer"},"counts":{"properties":{"activity":{"minimum":0,"type":"integer"},"organization":{"minimum":0,"type":"integer"},"session":{"minimum":0,"type":"integer"}},"required":["organization","activity","session"],"type":"object"},"exact":{"type":"integer"},"featureType":{"enum":["point","cluster"]},"groupId":{"type":"string"},"name":{"type":["string","null"]},"recordId":{"format":"uuid","type":"string"},"targetKind":{"enum":["organization","activity","session"]}},"type":"object"},"type":{"const":"Feature"}},"required":["type","id","geometry","properties"],"type":"object"},"type":"array"},"grouping":{"properties":{"cellDegrees":{"type":"number"},"maxFeatures":{"type":"integer"},"resolution":{"type":"integer"}},"type":"object"},"pointCoordinates":{"description":"Current responses use source for full stored precision of disclosed coordinates. rounded_to_two_decimal_places remains readable in historical saved metadata. Source quality is described separately.","enum":["source","rounded_to_two_decimal_places"]},"preview":{"properties":{"pageSize":{"type":"integer"},"sample":{"const":true}},"type":"object"},"region":{"type":"object"},"tier":{"type":"string"},"type":{"const":"FeatureCollection"},"viewport":{"properties":{"approximate":{"type":"integer"},"bounds":{"items":{"type":"number"},"maxItems":4,"minItems":4,"type":"array"},"count":{"type":"integer"},"counts":{"properties":{"activity":{"minimum":0,"type":"integer"},"organization":{"minimum":0,"type":"integer"},"session":{"minimum":0,"type":"integer"}},"required":["organization","activity","session"],"type":"object"},"exact":{"type":"integer"},"scope":{"const":"intersecting_grid_cells"}},"type":"object"}},"required":["type","features","coverage","viewport","grouping","pointCoordinates"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}},"application/vnd.schoolsout.map+cbor;version=1":{"schema":{"properties":{"data":{"properties":{"campPoints":{"description":"Present only when includeCampPoints=true. Organization-only points within the exact requested projected-coordinate bounds; excludes approximate locations and children.","properties":{"features":{"items":{"properties":{"geometry":{"properties":{"coordinates":{"items":{"type":"number"},"maxItems":2,"minItems":2,"type":"array"},"type":{"const":"Point"}},"required":["type","coordinates"],"type":"object"},"id":{"description":"Organization UUID; distinct organizations retain distinct IDs at a shared coordinate.","format":"uuid","type":"string"},"properties":{"additionalProperties":false,"properties":{"name":{"description":"Present only when includeCampNames=true and the camp name is disclosed. Existing viewer-level text scrubbing and preview name masks apply; missing/hidden names are omitted without an identifier fallback.","type":"string"},"scoreBand":{"description":"Present only when includeCampScores=true. Uses the persisted organization score and the same bands as score details. Missing prepared scores, restricted accounts, and every preview receive unavailable.","enum":["weak","fair","good","strong","unavailable"],"type":"string"}},"type":"object"},"type":{"const":"Feature"}},"required":["type","id","geometry","properties"],"type":"object"},"maxItems":100000,"type":"array"},"type":{"const":"FeatureCollection"}},"required":["type","features"],"type":"object"},"coverage":{"properties":{"approximate":{"minimum":0,"type":"integer"},"byKind":{"additionalProperties":{"properties":{"approximate":{"minimum":0,"type":"integer"},"exact":{"minimum":0,"type":"integer"},"located":{"minimum":0,"type":"integer"},"total":{"minimum":0,"type":"integer"},"unlocated":{"minimum":0,"type":"integer"}},"required":["total","located","exact","approximate","unlocated"],"type":"object"},"type":"object"},"exact":{"minimum":0,"type":"integer"},"located":{"minimum":0,"type":"integer"},"total":{"minimum":0,"type":"integer"},"unlocated":{"minimum":0,"type":"integer"}},"type":"object"},"features":{"items":{"properties":{"geometry":{"properties":{"coordinates":{"items":{"type":"number"},"maxItems":2,"minItems":2,"type":"array"},"type":{"const":"Point"}},"type":"object"},"id":{"type":"string"},"properties":{"properties":{"approximate":{"type":"integer"},"coordinatePrecision":{"$ref":"#/components/schemas/CoordinatePrecision"},"count":{"minimum":1,"type":"integer"},"counts":{"properties":{"activity":{"minimum":0,"type":"integer"},"organization":{"minimum":0,"type":"integer"},"session":{"minimum":0,"type":"integer"}},"required":["organization","activity","session"],"type":"object"},"exact":{"type":"integer"},"featureType":{"enum":["point","cluster"]},"groupId":{"type":"string"},"name":{"type":["string","null"]},"recordId":{"format":"uuid","type":"string"},"targetKind":{"enum":["organization","activity","session"]}},"type":"object"},"type":{"const":"Feature"}},"required":["type","id","geometry","properties"],"type":"object"},"type":"array"},"grouping":{"properties":{"cellDegrees":{"type":"number"},"maxFeatures":{"type":"integer"},"resolution":{"type":"integer"}},"type":"object"},"pointCoordinates":{"description":"Current responses use source for full stored precision of disclosed coordinates. rounded_to_two_decimal_places remains readable in historical saved metadata. Source quality is described separately.","enum":["source","rounded_to_two_decimal_places"]},"preview":{"properties":{"pageSize":{"type":"integer"},"sample":{"const":true}},"type":"object"},"region":{"type":"object"},"tier":{"type":"string"},"type":{"const":"FeatureCollection"},"viewport":{"properties":{"approximate":{"type":"integer"},"bounds":{"items":{"type":"number"},"maxItems":4,"minItems":4,"type":"array"},"count":{"type":"integer"},"counts":{"properties":{"activity":{"minimum":0,"type":"integer"},"organization":{"minimum":0,"type":"integer"},"session":{"minimum":0,"type":"integer"}},"required":["organization","activity","session"],"type":"object"},"exact":{"type":"integer"},"scope":{"const":"intersecting_grid_cells"}},"type":"object"}},"required":["type","features","coverage","viewport","grouping","pointCoordinates"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}},"application/vnd.schoolsout.map-stream+cbor;version=1":{"description":"Finite length-prefixed CBOR frames: start, zero or more points, result, complete. Payload length is unsigned uint32 big-endian, at most 1 MiB; optional gzip spans the whole stream. A terminal error replaces successful completion.","schema":{"format":"binary","type":"string"}},"application/vnd.schoolsout.map-stream+cbor;version=2":{"description":"Requires includeCampPoints=true. Finite length-prefixed CBOR frames: start with ordered columns, zero or more points frames with positional rows, then complete. Payload length is unsigned uint32 big-endian, at most 1 MiB; optional gzip spans the whole stream. No map metadata result is calculated. A terminal error replaces successful completion. Selected-region validation failures remain pre-stream HTTP 400 responses.","schema":{"format":"binary","type":"string"}}},"description":"Authorized geographic result.","headers":{"ETag":{"description":"Weak validator bound to query, representation, compression, and disclosure. Retain streamed validators only after successful completion.","schema":{"type":"string"}},"X-Map-Revision":{"description":"Committed dependency revision shared by compatible disclosure and source scopes.","schema":{"type":"string"}}}},"304":{"description":"The completed representation remains current; no response body.","headers":{"ETag":{"schema":{"type":"string"}},"X-Map-Revision":{"schema":{"type":"string"}}}},"400":{"description":"Invalid bounds, filters, cursor, or unavailable selected source boundary. Also returned for malformed, repeated, over-complex or incorrectly typed filter JSON, an unsupported filterKind, or filterKind without filter."},"401":{"description":"Authentication required."},"403":{"description":"Plan, field, or preview capability refuses the read. Structured filter fields and owner relationships must be available under current plan and preview disclosure."},"413":{"description":"Too many camp locations to display. Zoom in or add filters; no partial camp-point collection is returned."},"429":{"description":"Read allowance exceeded."},"503":{"description":"Database map cache is preparing. The response code is map_cache_warming; retry after a short delay."}},"summary":"Browse all canonical entity kinds on a map","tags":["Internal Explorer map"],"x-auth":"Starter or above with current catalog access. Preview requires explorer.browse_masked and preserves the fixed disclosed sample.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/canonical/map\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"bbox=-122.5,47.4,-122.2,47.8\" \\\n  --data-urlencode \"zoom=11\" \\\n  --data-urlencode \"region=WA\"","title":"Read Seattle-area map cells for Washington records"},{"title":"Map camps with a matching session quote and age range","code":"curl --get \"https://apis.schoolsoutapp.com/api/canonical/map\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"bbox=-125,24,-66,50\" \\\n  --data-urlencode \"zoom=3\" \\\n  --data-urlencode \"includeCampPoints=true\" \\\n  --data-urlencode \"filterKind=session\" \\\n  --data-urlencode 'filter={\"all\":[{\"field\":\"age_range_years\",\"op\":\"contains\",\"value\":10},{\"price\":{\"maximum\":400,\"currency\":\"USD\",\"basis\":\"week\"}}]}'"}],"x-internal":true}},"/api/canonical/map/stream":{"get":{"description":"Streams the authorized camp-point snapshot once, then compact point upserts and removals over SSE. Requires includeCampPoints=true and the same bbox, zoom, filters, names, scores, tier and preview disclosure as the finite map route. Each generation begins with event:start containing version=1, mode=snapshot or delta, revision, sourceRevision, bounds, columns, and fromRevision for deltas. Columns are id, longitude, latitude, optionally name, then optionally scoreBand. event:points contains zero-based sequence, rows of positional upsert tuples, and removeIds (empty for snapshots). event:complete contains revision, pointCount, batchCount, upsertCount and removeCount, and is the only event carrying id:revision. Clients commit data and the cursor only after validating the complete generation. First-load batches may be displayed provisionally; replacements and deltas retain the completed map until complete. Send the last committed cursor in Last-Event-ID to resume. A matching current cursor returns event:ready with revision and sourceRevision and no point download; retained history produces a delta; missing or evicted history produces a replacement snapshot. The cursor is query/disclosure scoped and opaque. sourceRevision is the separate equality token used by finite map metadata. Database revision and points are read from the same snapshot. The server checks dependency fences and shares point builds only when dependencies change; idle connections do not query or transmit the full point population repeatedly. Snapshot history is bounded API-process memory, not durable replay; restarts or another replica can require a replacement. Connections are bounded so reconnects renew authorization, and heartbeat comments carry no data changes. Pre-stream failures use ordinary HTTP JSON errors; terminal event:error contains code and message, optionally status. Incomplete generations never advance the cursor. HTTP 401/402/403 or access refusals must discard retained protected data. No worker or canonical write is started by a subscription. Structured filter JSON uses filterKind=organization (default), activity, or session. Matching children select their effectively owning camps, with direct session organization before activity fallback. The cohort includes those camps and all disclosed effectively owned activities/sessions, including children that did not match the tree, before existing legacy filters and per-record geography narrow it using AND. Camp dots use the camp own coordinates. Preserve both parameters across snapshots, viewport reads, members and summaries. Original tree limits, fixed preview disclosure and field permissions apply; the internal camp projection consumes no extra predicate budget. This selection is identical across JSON, CBOR, finite v1/v2 and live SSE transports; global text-search suggestions stay separate.","parameters":[{"description":"West,south,east,north in longitude/latitude degrees. West greater than east crosses the antimeridian.","in":"query","name":"bbox","required":true,"schema":{"example":"-125,24,-66,50","type":"string"}},{"description":"Map zoom used to choose bounded display detail.","in":"query","name":"zoom","required":true,"schema":{"maximum":22,"minimum":0,"type":"number"}},{"description":"Must be true for the camp-point event stream.","in":"query","name":"includeCampPoints","required":true,"schema":{"type":"boolean","const":true}},{"description":"Add disclosed names to campPoints using the existing viewer-level text scrubbing and preview masks. Requires includeCampPoints=true. Hidden/missing names are omitted; omitted/false skips name reads.","in":"query","name":"includeCampNames","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Add persisted organization score bands to campPoints. Requires includeCampPoints=true. Missing prepared scores, restricted accounts, and every preview receive unavailable; omitted/false skips score-band reads.","in":"query","name":"includeCampScores","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"Case-insensitive search in each entity kind using its permitted canonical search fields.","explode":true,"in":"query","name":"q","required":false,"schema":{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Each record’s own city, case-insensitive exact name or hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Each record’s own recorded region; distinct from the selected polygon.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on each matching record; categories are independent across organizations, activities, and sessions.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Matches the record’s own stated inclusive configuration range.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Organization identity or child lineage.","in":"query","name":"organizationId","required":false,"schema":{"type":"string"}},{"description":"Activity identity or matching ancestor/descendant activity.","in":"query","name":"activityId","required":false,"schema":{"type":"string"}},{"description":"Matching activity skill level.","in":"query","name":"skillLevel","required":false,"schema":{"type":"string"}},{"description":"Matching activity format.","in":"query","name":"format","required":false,"schema":{"type":"string"}},{"description":"Matching activity seasonality.","in":"query","name":"seasonality","required":false,"schema":{"type":"string"}},{"description":"Matching session registration status; its field access gate applies.","in":"query","name":"registrationStatus","required":false,"schema":{"type":"string"}},{"description":"Matching sessions ending on or after this date.","in":"query","name":"from","required":false,"schema":{"type":"string"}},{"description":"Matching sessions starting on or before this date.","in":"query","name":"to","required":false,"schema":{"type":"string"}},{"description":"Selected source boundary kind; requires regionCode and regionDataset.","in":"query","name":"regionKind","required":false,"schema":{"enum":["state","zip","metro","county","city","neighborhood"],"type":"string"}},{"description":"Stable source identifier for the selected boundary.","in":"query","name":"regionCode","required":false,"schema":{"type":"string"}},{"description":"Immutable imported dataset ID. Retired installed datasets remain selectable.","in":"query","name":"regionDataset","required":false,"schema":{"type":"string"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Requires a direct staff or ADMIN account; service delegation, machine keys, and previews are refused. Filters organizations by one shared camp collection; map routes include coherently owned descendants.","in":"query","name":"collectionId","required":false,"schema":{"format":"uuid","type":"string"}},{"name":"Last-Event-ID","in":"header","required":false,"description":"The last fully validated and committed stream revision. Partial generations must not advance this cursor. Missing retained history causes a replacement snapshot.","schema":{"type":"string","maxLength":128}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON CanonicalFilter tree, sent once and evaluated against filterKind (organization by default). A matching activity/session selects its effectively owning camp; a session direct organization wins before activity fallback. The resulting cohort includes selected camps and all their disclosed effectively owned children, including nonmatching children, before legacy filters and geography narrow it using AND. Camp dots use each camp own coordinates. Original tree limits and current field/preview disclosure apply; the internal camp projection consumes no extra depth or byte budget. Send the same filter and filterKind on map points, metadata, members and summary reads.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"filterKind","in":"query","required":false,"description":"Root entity type for filter. Requires filter and appears once. Organization roots select matching camps; activity/session roots select camps owning matching children. This does not limit mixed metadata, members or summary counts to matching children. Every camp dot retains its own address-grade location.","schema":{"type":"string","enum":["organization","activity","session"],"default":"organization"}}],"responses":{"200":{"description":"SSE snapshot and delta generations, unchanged ready events, and heartbeat comments.","content":{"text/event-stream":{"schema":{"type":"string"}}}},"400":{"description":"Invalid bounds, filters, cursor, or unavailable selected source boundary. Also returned for malformed, repeated, over-complex or incorrectly typed filter JSON, an unsupported filterKind, or filterKind without filter."},"401":{"description":"Authentication required."},"403":{"description":"Plan, field, or preview capability refuses the read. Structured filter fields and owner relationships must be available under current plan and preview disclosure."},"413":{"description":"Too many camp locations to display. Zoom in or add filters; no partial camp-point collection is returned."},"429":{"description":"Read allowance exceeded."},"503":{"description":"Database map cache is preparing. The response code is map_cache_warming; retry after a short delay."}},"summary":"Stream live camp-point additions, changes and removals","tags":["Internal Explorer map"],"x-auth":"Starter or above with current catalog access. Preview requires explorer.browse_masked and preserves the fixed disclosed sample.","x-curl-examples":[{"title":"Subscribe to live camp points","code":"curl -N --get \"https://apis.schoolsoutapp.com/api/canonical/map/stream\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"bbox=-180,-90,180,90\" \\\n  --data-urlencode \"zoom=0\" \\\n  --data-urlencode \"includeCampPoints=true\" \\\n  --data-urlencode \"includeCampNames=true\" \\\n  --data-urlencode \"includeCampScores=true\""}],"x-internal":true}},"/api/canonical/map/boundaries":{"get":{"description":"Returns bounded simplified GeoJSON for display, with immutable datasetId/kind/code identity, bounds, source, vintage, availability, and explicit truncation. Supply bbox, q, code, or point. Point lookup covers the stored source polygon, including edges, independently of viewport, display simplification, and overlay truncation. Overlapping point candidates retain stable code order and existing feature/byte budgets. Selection uses the stored unsimplified geometry, never this display outline. Metro means Census metropolitan statistical area. City outlines distinguish incorporated places from Census-designated places. Neighborhood coverage exists only where authoritative local sources have been imported. Runtime reads never fetch or replace reference datasets. Display geometry and source bounds are prepared in the database outside request processing. Point and region membership retain original source polygons. Pending preparation returns HTTP 503 with code=map_cache_warming; callers may retry this state. Successes optionally use application/vnd.schoolsout.map+cbor;version=1 when explicitly requested with Accept at positive quality at least as high as JSON. JSON remains the default and all errors remain JSON. The data model and authorization are unchanged; responses vary on Accept and Accept-Encoding and retain private, no-store. Successful finished responses may be reused from a bounded per-process memory cache keyed by normalized options, current disclosure policy, representation, and compression; response bodies do not survive a restart. Every request still authenticates and checks access. Source, live eligibility, score, geography, and projection changes invalidate dependent responses; reuse expires by its maximum age and the next UTC midnight. Cache failures fall back to normal reads. Private/no-store and JSON error behavior remain unchanged. X-Map-Revision, when available, is an opaque equality token scoped to relevant source changes, disclosure, policy, and UTC day; clients must not parse it. Successful responses carry a weak ETag bound to normalized options, disclosure, representation, and compression. Send it with If-None-Match to revalidate; after current authorization and a fresh source-fence check, a match returns HTTP 304 with no body and without running the map data query. Retain a streamed ETag only after its complete frame passes sequence and count validation. Revision tokens fence server response reuse and remain available to clients; metadata revision changes do not automatically replace an already loaded Explorer point snapshot. Score writes invalidate requests with minimumScore or maximumScore filters and requests with includeCampScores=true. Migration 0048 indexes boundary provenance lookup without limiting provenance values. Rows whose combined UTF-8 octet length across dataset_id, kind, source, source_url, and vintage is at most 2,000 bytes use a covering btree index on all five keys; larger rows use a complementary partial btree index on dataset_id and kind. MapBoundaries combines those disjoint bounded and overflow paths with UNION ALL, then retains the existing exact distinct source tuples and ordering. The threshold only routes index use; provenance values are never rejected or truncated. Apply prepare migrations 0047 then 0048 before deploying the matching API code.","parameters":[{"description":"Boundary layer.","in":"query","name":"kind","required":true,"schema":{"enum":["state","zip","metro","county","city","neighborhood"],"type":"string"}},{"description":"West,south,east,north in longitude/latitude degrees. West greater than east crosses the antimeridian.","in":"query","name":"bbox","required":false,"schema":{"example":"-125,24,-66,50","type":"string"}},{"description":"One finite longitude,latitude pair within longitude ±180 and latitude ±85. Exclusive with bbox, code, and q. Returns source polygons covering the point, including edges; zoom controls display detail only.","in":"query","name":"point","required":false,"schema":{"example":"-122.3321,47.6062","type":"string"}},{"description":"Map zoom used to choose bounded display detail.","in":"query","name":"zoom","required":false,"schema":{"maximum":22,"minimum":0,"type":"number"}},{"description":"Installed immutable dataset ID; omitted uses the active snapshot.","in":"query","name":"datasetId","required":false,"schema":{"type":"string"}},{"description":"Search source names/codes instead of a viewport.","in":"query","name":"q","required":false,"schema":{"type":"string"}},{"description":"Return one source boundary and its bounds instead of a viewport.","in":"query","name":"code","required":false,"schema":{"type":"string"}},{"description":"Revalidate a completed response using its ETag. Current authorization and source dependencies are checked before an unchanged response returns 304.","in":"header","name":"If-None-Match","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"availability":{"type":"object"},"datasetId":{"type":"string"},"datasetVersion":{"type":"string"},"features":{"items":{"type":"object"},"type":"array"},"geometryRole":{"const":"display"},"selectionGeometry":{"const":"source"},"truncated":{"type":"boolean"},"type":{"const":"FeatureCollection"}},"required":["type","features","availability","truncated","geometryRole","selectionGeometry"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}},"application/vnd.schoolsout.map+cbor;version=1":{"schema":{"properties":{"data":{"properties":{"availability":{"type":"object"},"datasetId":{"type":"string"},"datasetVersion":{"type":"string"},"features":{"items":{"type":"object"},"type":"array"},"geometryRole":{"const":"display"},"selectionGeometry":{"const":"source"},"truncated":{"type":"boolean"},"type":{"const":"FeatureCollection"}},"required":["type","features","availability","truncated","geometryRole","selectionGeometry"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Authorized geographic result.","headers":{"ETag":{"description":"Weak validator bound to query, representation, compression, and disclosure. Retain streamed validators only after successful completion.","schema":{"type":"string"}},"X-Map-Revision":{"description":"Committed dependency revision shared by compatible disclosure and source scopes.","schema":{"type":"string"}}}},"304":{"description":"The completed representation remains current; no response body.","headers":{"ETag":{"schema":{"type":"string"}},"X-Map-Revision":{"schema":{"type":"string"}}}},"400":{"description":"Invalid bounds, filters, cursor, or unavailable selected source boundary."},"401":{"description":"Authentication required."},"403":{"description":"Plan, field, or preview capability refuses the read."},"429":{"description":"Read allowance exceeded."},"503":{"description":"Database map cache is preparing. The response code is map_cache_warming; retry after a short delay."}},"summary":"Browse, search, or resolve imported region outlines","tags":["Internal Explorer map"],"x-auth":"Starter or above with current catalog access. Preview requires explorer.browse_masked and preserves the fixed disclosed sample.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/canonical/map/boundaries\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"kind=city\" \\\n  --data-urlencode \"point=-122.3321,47.6062\" \\\n  --data-urlencode \"zoom=11\"","title":"Resolve the city outlines covering a point"}],"x-internal":true}},"/api/canonical/map/members":{"get":{"description":"Use the map response groupId and exactly the same catalog and region filters. Complete cell membership is paginated by typed record identity; co-located entries remain accessible at maximum zoom. Preview pagination never escapes its fixed disclosed population. Reads the same durable map projection and masking rules as the map. Initial preparation returns HTTP 503 with code=map_cache_warming. Successes optionally use application/vnd.schoolsout.map+cbor;version=1 when explicitly requested with Accept at positive quality at least as high as JSON. JSON remains the default and all errors remain JSON. The data model and authorization are unchanged; responses vary on Accept and Accept-Encoding and retain private, no-store. Successful finished responses may be reused from a bounded per-process memory cache keyed by normalized options, current disclosure policy, representation, and compression; response bodies do not survive a restart. Every request still authenticates and checks access. Source, live eligibility, score, geography, and projection changes invalidate dependent responses; reuse expires by its maximum age and the next UTC midnight. Cache failures fall back to normal reads. Private/no-store and JSON error behavior remain unchanged. X-Map-Revision, when available, is an opaque equality token scoped to relevant source changes, disclosure, policy, and UTC day; clients must not parse it. Successful responses carry a weak ETag bound to normalized options, disclosure, representation, and compression. Send it with If-None-Match to revalidate; after current authorization and a fresh source-fence check, a match returns HTTP 304 with no body and without running the map data query. Retain a streamed ETag only after its complete frame passes sequence and count validation. Revision tokens fence server response reuse and remain available to clients; metadata revision changes do not automatically replace an already loaded Explorer point snapshot. Score writes invalidate requests with minimumScore or maximumScore filters and requests with includeCampScores=true. Map and member reads exclude identities with committed source work still queued and overlay those identities from current source rows. Projection state and the live overlay share one repeatable-read snapshot; a proven clean snapshot takes the saved-row fast path. ageYears uses whole completed years. The legacy ageMonths filter remains available; month-shaped aliases derived from canonical inclusive year bounds use [yearMin*12,yearMax*12+11]. collectionId is staff-only; collections contain organizations and do not infer activity or session category labels. Structured filter JSON uses filterKind=organization (default), activity, or session. Matching children select their effectively owning camps, with direct session organization before activity fallback. The cohort includes those camps and all disclosed effectively owned activities/sessions, including children that did not match the tree, before existing legacy filters and per-record geography narrow it using AND. Camp dots use the camp own coordinates. Preserve both parameters across snapshots, viewport reads, members and summaries. Original tree limits, fixed preview disclosure and field permissions apply; the internal camp projection consumes no extra predicate budget. This selection is identical across JSON, CBOR, finite v1/v2 and live SSE transports; global text-search suggestions stay separate.","parameters":[{"description":"groupId returned by the map.","in":"query","name":"group","required":true,"schema":{"type":"string"}},{"description":"Member page size.","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"nextCursor returned by the previous page.","in":"query","name":"after","required":false,"schema":{"type":"string"}},{"description":"Case-insensitive search in each entity kind using its permitted canonical search fields.","explode":true,"in":"query","name":"q","required":false,"schema":{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Each record’s own city, case-insensitive exact name or hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Each record’s own recorded region; distinct from the selected polygon.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on each matching record; categories are independent across organizations, activities, and sessions.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Matches the record’s own stated inclusive configuration range.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Organization identity or child lineage.","in":"query","name":"organizationId","required":false,"schema":{"type":"string"}},{"description":"Activity identity or matching ancestor/descendant activity.","in":"query","name":"activityId","required":false,"schema":{"type":"string"}},{"description":"Matching activity skill level.","in":"query","name":"skillLevel","required":false,"schema":{"type":"string"}},{"description":"Matching activity format.","in":"query","name":"format","required":false,"schema":{"type":"string"}},{"description":"Matching activity seasonality.","in":"query","name":"seasonality","required":false,"schema":{"type":"string"}},{"description":"Matching session registration status; its field access gate applies.","in":"query","name":"registrationStatus","required":false,"schema":{"type":"string"}},{"description":"Matching sessions ending on or after this date.","in":"query","name":"from","required":false,"schema":{"type":"string"}},{"description":"Matching sessions starting on or before this date.","in":"query","name":"to","required":false,"schema":{"type":"string"}},{"description":"Selected source boundary kind; requires regionCode and regionDataset.","in":"query","name":"regionKind","required":false,"schema":{"enum":["state","zip","metro","county","city","neighborhood"],"type":"string"}},{"description":"Stable source identifier for the selected boundary.","in":"query","name":"regionCode","required":false,"schema":{"type":"string"}},{"description":"Immutable imported dataset ID. Retired installed datasets remain selectable.","in":"query","name":"regionDataset","required":false,"schema":{"type":"string"}},{"description":"Revalidate a completed response using its ETag. Current authorization and source dependencies are checked before an unchanged response returns 304.","in":"header","name":"If-None-Match","required":false,"schema":{"type":"string"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Requires a direct staff or ADMIN account; service delegation, machine keys, and previews are refused. Filters organizations by one shared camp collection; map routes include coherently owned descendants.","in":"query","name":"collectionId","required":false,"schema":{"format":"uuid","type":"string"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON CanonicalFilter tree, sent once and evaluated against filterKind (organization by default). A matching activity/session selects its effectively owning camp; a session direct organization wins before activity fallback. The resulting cohort includes selected camps and all their disclosed effectively owned children, including nonmatching children, before legacy filters and geography narrow it using AND. Camp dots use each camp own coordinates. Original tree limits and current field/preview disclosure apply; the internal camp projection consumes no extra depth or byte budget. Send the same filter and filterKind on map points, metadata, members and summary reads.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"filterKind","in":"query","required":false,"description":"Root entity type for filter. Requires filter and appears once. Organization roots select matching camps; activity/session roots select camps owning matching children. This does not limit mixed metadata, members or summary counts to matching children. Every camp dot retains its own address-grade location.","schema":{"type":"string","enum":["organization","activity","session"],"default":"organization"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"groupId":{"type":"string"},"members":{"items":{"properties":{"coordinatePrecision":{"$ref":"#/components/schemas/CoordinatePrecision"},"id":{"format":"uuid","type":"string"},"name":{"type":["string","null"]},"targetKind":{"enum":["organization","activity","session"]}},"required":["targetKind","id","name","coordinatePrecision"],"type":"object"},"type":"array"},"nextCursor":{"type":["string","null"]},"total":{"type":"integer"}},"required":["members","total","nextCursor","groupId"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}},"application/vnd.schoolsout.map+cbor;version=1":{"schema":{"properties":{"data":{"properties":{"groupId":{"type":"string"},"members":{"items":{"properties":{"coordinatePrecision":{"$ref":"#/components/schemas/CoordinatePrecision"},"id":{"format":"uuid","type":"string"},"name":{"type":["string","null"]},"targetKind":{"enum":["organization","activity","session"]}},"required":["targetKind","id","name","coordinatePrecision"],"type":"object"},"type":"array"},"nextCursor":{"type":["string","null"]},"total":{"type":"integer"}},"required":["members","total","nextCursor","groupId"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Authorized geographic result.","headers":{"ETag":{"description":"Weak validator bound to query, representation, compression, and disclosure. Retain streamed validators only after successful completion.","schema":{"type":"string"}},"X-Map-Revision":{"description":"Committed dependency revision shared by compatible disclosure and source scopes.","schema":{"type":"string"}}}},"304":{"description":"The completed representation remains current; no response body.","headers":{"ETag":{"schema":{"type":"string"}},"X-Map-Revision":{"schema":{"type":"string"}}}},"400":{"description":"Invalid bounds, filters, cursor, or unavailable selected source boundary. Also returned for malformed, repeated, over-complex or incorrectly typed filter JSON, an unsupported filterKind, or filterKind without filter."},"401":{"description":"Authentication required."},"403":{"description":"Plan, field, or preview capability refuses the read. Structured filter fields and owner relationships must be available under current plan and preview disclosure."},"429":{"description":"Read allowance exceeded."},"503":{"description":"Database map cache is preparing. The response code is map_cache_warming; retry after a short delay."}},"summary":"Read the records in one map group","tags":["Internal Explorer map"],"x-auth":"Starter or above with current catalog access. Preview requires explorer.browse_masked and preserves the fixed disclosed sample.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/canonical/map/members\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"group=$MAP_GROUP_ID\" \\\n  --data-urlencode \"region=WA\" \\\n  --data-urlencode \"limit=50\"","title":"Read the records in a map group returned with the same filters"}],"x-internal":true}},"/api/canonical/map/summary":{"get":{"description":"Uses the same masked, filtered mixed-entity cohort and unsimplified selected-region boundary as the map. Region counts are independent of bbox, zoom, and pagination. Paid data access is required; investor preview is not supported. Accessible coordinates use full stored precision on every plan before membership; source quality still limits geographic accuracy. Selected-region membership uses distance in meters from the viewer-masked stored point to the unsimplified boundary, with inclusive layer tolerances initially 100 m for neighborhoods, 500 m for cities/ZIPs, 2 km for counties, 5 km for metros, and 10 km for states. A point-centered tolerance circle may partially overlap the region; the center need not be inside, and records may match multiple regions. The same rule applies to address-grade and ZIP/state approximate points, without source-area polygon intersections or zoom dependence. Unknown, missing, masked, and invalid locations are excluded. Approximate quality remains separate. This does not change structured canonical/Ask location classifications. Category buckets count distinct records and may overlap. Activity age bands overlap; missing ages are reported separately. Upcoming sessions start on or after the UTC query date. Category and week distributions are bounded and expose totalBuckets so clients can disclose omitted buckets. asOf records the original evaluation time, retained on cache reuse, not when source facts were verified. A missing or invalid region is an error, never a successful zero summary. Accepts the same cohort filters as the map: q, category, city, region, ageMonths, grade, organizationId, activityId, skillLevel, format, seasonality, from, to, registrationStatus, minimumScore, and maximumScore. No research is generated or saved. Successes optionally use application/vnd.schoolsout.map+cbor;version=1 when explicitly requested with Accept at positive quality at least as high as JSON. JSON remains the default and all errors remain JSON. The data model and authorization are unchanged; responses vary on Accept and Accept-Encoding and retain private, no-store. Successful finished responses may be reused from a bounded per-process memory cache keyed by normalized options, current disclosure policy, representation, and compression; response bodies do not survive a restart. Every request still authenticates and checks access. Source, live eligibility, score, geography, and projection changes invalidate dependent responses; reuse expires by its maximum age and the next UTC midnight. Cache failures fall back to normal reads. Private/no-store and JSON error behavior remain unchanged. A reused summary preserves its original asOf evaluation timestamp; asOf is not request time or verification time. X-Map-Revision, when available, is an opaque equality token scoped to relevant source changes, disclosure, policy, and UTC day; clients must not parse it. Successful responses carry a weak ETag bound to normalized options, disclosure, representation, and compression. Send it with If-None-Match to revalidate; after current authorization and a fresh source-fence check, a match returns HTTP 304 with no body and without running the map data query. Retain a streamed ETag only after its complete frame passes sequence and count validation. Revision tokens fence server response reuse and remain available to clients; metadata revision changes do not automatically replace an already loaded Explorer point snapshot. Score writes invalidate requests with minimumScore or maximumScore filters and requests with includeCampScores=true. Map and member reads exclude identities with committed source work still queued and overlay those identities from current source rows. Projection state and the live overlay share one repeatable-read snapshot; a proven clean snapshot takes the saved-row fast path. collectionId is staff-only; collections contain organizations and do not infer activity or session category labels. Structured filter JSON uses filterKind=organization (default), activity, or session. Matching children select their effectively owning camps, with direct session organization before activity fallback. The cohort includes those camps and all disclosed effectively owned activities/sessions, including children that did not match the tree, before existing legacy filters and per-record geography narrow it using AND. Camp dots use the camp own coordinates. Preserve both parameters across snapshots, viewport reads, members and summaries. Original tree limits, fixed preview disclosure and field permissions apply; the internal camp projection consumes no extra predicate budget. This selection is identical across JSON, CBOR, finite v1/v2 and live SSE transports; global text-search suggestions stay separate.","parameters":[{"description":"Selected geography kind: state, ZIP, metro, county, city, or neighborhood.","in":"query","name":"regionKind","required":true,"schema":{"type":"string"}},{"description":"Code within the selected geography dataset.","in":"query","name":"regionCode","required":true,"schema":{"type":"string"}},{"description":"Immutable imported geography dataset ID. No active-version substitution.","in":"query","name":"regionDataset","required":true,"schema":{"type":"string"}},{"description":"Revalidate a completed response using its ETag. Current authorization and source dependencies are checked before an unchanged response returns 304.","in":"header","name":"If-None-Match","required":false,"schema":{"type":"string"}},{"description":"Requires a direct staff or ADMIN account; service delegation, machine keys, and previews are refused. Filters organizations by one shared camp collection; map routes include coherently owned descendants.","in":"query","name":"collectionId","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"Returns organizations whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON CanonicalFilter tree, sent once and evaluated against filterKind (organization by default). A matching activity/session selects its effectively owning camp; a session direct organization wins before activity fallback. The resulting cohort includes selected camps and all their disclosed effectively owned children, including nonmatching children, before legacy filters and geography narrow it using AND. Camp dots use each camp own coordinates. Original tree limits and current field/preview disclosure apply; the internal camp projection consumes no extra depth or byte budget. Send the same filter and filterKind on map points, metadata, members and summary reads.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"filterKind","in":"query","required":false,"description":"Root entity type for filter. Requires filter and appears once. Organization roots select matching camps; activity/session roots select camps owning matching children. This does not limit mixed metadata, members or summary counts to matching children. Every camp dot retains its own address-grade location.","schema":{"type":"string","enum":["organization","activity","session"],"default":"organization"}},{"description":"Case-insensitive search in each entity kind using its permitted canonical search fields.","explode":true,"in":"query","name":"q","required":false,"schema":{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Each record’s own city, case-insensitive exact name or hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Each record’s own recorded region; distinct from the selected polygon.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on each matching record; categories are independent across organizations, activities, and sessions.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Matches the record’s own stated inclusive configuration range.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Organization identity or child lineage.","in":"query","name":"organizationId","required":false,"schema":{"type":"string"}},{"description":"Activity identity or matching ancestor/descendant activity.","in":"query","name":"activityId","required":false,"schema":{"type":"string"}},{"description":"Matching activity skill level.","in":"query","name":"skillLevel","required":false,"schema":{"type":"string"}},{"description":"Matching activity format.","in":"query","name":"format","required":false,"schema":{"type":"string"}},{"description":"Matching activity seasonality.","in":"query","name":"seasonality","required":false,"schema":{"type":"string"}},{"description":"Matching session registration status; its field access gate applies.","in":"query","name":"registrationStatus","required":false,"schema":{"type":"string"}},{"description":"Matching sessions ending on or after this date.","in":"query","name":"from","required":false,"schema":{"type":"string"}},{"description":"Matching sessions starting on or before this date.","in":"query","name":"to","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Summary envelope: success true and data with region (kind, code, datasetId, name), asOf, and metrics. Metrics include counts and location membership per entity kind; organization/activity category distributions; activityAges; upcomingSessions (total, undated, nextStartDate, weeks); and per-kind missing field counts. Distribution buckets contain value/count and totalBuckets. Empty populations retain zeros and empty arrays.","headers":{"ETag":{"description":"Weak validator bound to query, representation, compression, and disclosure. Retain streamed validators only after successful completion.","schema":{"type":"string"}},"X-Map-Revision":{"description":"Committed dependency revision shared by compatible disclosure and source scopes.","schema":{"type":"string"}}}},"304":{"description":"The completed representation remains current; no response body.","headers":{"ETag":{"schema":{"type":"string"}},"X-Map-Revision":{"schema":{"type":"string"}}}},"400":{"description":"Invalid or missing region selection or filter. Also returned for malformed, repeated, over-complex or incorrectly typed filter JSON, an unsupported filterKind, or filterKind without filter."},"401":{"description":"Authentication required."},"403":{"description":"Paid data access required or preview not supported. Structured filter fields and owner relationships must be available under current plan and preview disclosure."},"503":{"description":"Summary temporarily unavailable."}},"summary":"Summarize a selected Explorer region","tags":["Internal canonical queries"],"x-auth":"Starter or above with current catalog access. Investor preview sessions are refused.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/canonical/map/summary\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"regionKind=city\" \\\n  --data-urlencode \"regionCode=$REGION_CODE\" \\\n  --data-urlencode \"regionDataset=$REGION_DATASET_ID\"","title":"Summarize a region selected from the boundaries response"}],"x-internal":true}},"/api/canonical/query":{"post":{"description":"Accepts one read-only SELECT/WITH over permitted canonical views. Account access retains plan gates; machine keys are refused, and Free reaches these data through internal Ask only. location adds location_match and distance_meters to organizations, activities, and sessions without filtering rows. Filter or group classifications explicitly. Address-point distances use full stored coordinate precision on every plan; source quality still limits geographic accuracy. Current location metadata reports pointCoordinates=source; historical saved metadata may retain rounded_to_two_decimal_places. ZIP boundaries yield possible_area_match with null venue distance; state_coverage is broad and unresolved includes missing boundaries. All Ask users may receive approximate classifications without protected ZIPs, identifiers, geometry, or derivation metadata. Arbitrary spatial functions and physical geography tables remain inaccessible. Omitting location preserves prior behavior.","requestBody":{"content":{"application/json":{"examples":{"area":{"value":{"location":{"code":"98101","kind":"zip","radiusMeters":1000,"type":"area"},"sql":"select name, location_match, distance_meters from sessions where location_match in ('point_match','possible_area_match')"}},"point":{"value":{"location":{"latitude":47.6062,"longitude":-122.3321,"radiusMeters":5000,"type":"point"},"sql":"select location_match, count(*)::int from activities group by location_match"}}},"schema":{"properties":{"location":{"$ref":"#/components/schemas/LocationFilter"},"params":{"items":{},"type":"array"},"sql":{"type":"string"},"timeoutSeconds":{"type":"integer","minimum":15,"maximum":60,"description":"Statement timeout in seconds. Only the service credential without x-viewer-id may set it, for unattended background reads; every other caller receives 403 and keeps the 15-second default."}},"required":["sql"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"location":{"$ref":"#/components/schemas/LocationQueryMetadata"},"rowCount":{"type":"integer"},"rows":{"items":{"type":"object"},"type":"array"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Masked rows; location metadata is present only when a location filter was supplied."},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"402":{"description":"Direct canonical reads require a paid plan; Free is Ask-only."},"403":{"description":"Current account lacks access; machine keys are refused."},"503":{"description":"Scoring schema not ready or query unavailable; retry after setup."}},"security":[{"AccountCredential":[]}],"summary":"Run a masked canonical query with optional location classification","tags":["Internal canonical queries"],"x-auth":"Signed Intelligence session or current account credential. The current account plan is enforced; machine keys cannot execute SQL.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/canonical/query\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"sql\":\"select location_match, count(*)::int from activities group by location_match\",\"location\":{\"type\":\"point\",\"latitude\":47.6062,\"longitude\":-122.3321,\"radiusMeters\":5000}}'","title":"Count returned activity location classifications using an account credential"}],"x-internal":true}},"/api/canonical/reference":{"get":{"description":"Requires current staff or ADMIN operator access and rejects preview sessions. Reads the canonical PostgreSQL catalog in one read-only snapshot and combines it with deployed application definitions, including relational sources for structured values and response-only media galleries and image URLs. Documenting response enrichments does not add selectable SQL columns or change public record projections. Private no-store response; generatedAt is metadata read time, not record verification time.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/CanonicalReference"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Live reference with explicit coverage issues when schema and application metadata disagree.","headers":{"Cache-Control":{"description":"private, no-store","schema":{"type":"string"}}}},"401":{"description":"No valid credential."},"403":{"description":"Staff or ADMIN access required; preview sessions are not supported."},"500":{"description":"Live database metadata could not be read; no cached reference is substituted."},"503":{"description":"Reference support is not configured on this API release."}},"summary":"Read the live staff data model reference","tags":["Canonical"],"x-auth":"Current staff or ADMIN operator identity. Preview sessions are rejected.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/canonical/reference\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read the staff data model reference"}],"x-internal":true}},"/api/canonical/search/interpret":{"post":{"summary":"Interpret a plain-language catalog search","description":"Translate a submitted search into one useful supported canonical filter using GPT-6 Luna. Understandable requests receive a best-effort filter and usually no feedback. Optional feedback is reserved for an important note about a material interpretation assumption or approximation that changes expected results; routine defaults, normal interpretation, recaps, and generic caveats stay silent. Apply the ready filter without confirmation. Omitted constraints generally remain unrestricted, while missing necessary values may use reasonable defaults. Clarification is reserved for unintelligible or clearly misguided intent. An unrestricted request may return an id-present filter. The API validates every branch against the current account tier and preview disclosure before returning it; feedback never bypasses validation. The provider receives the search text, current UTC time, and permitted filter capabilities, never account credentials or catalog rows. Interpretation does not execute a data read. A clarification, malformed or disallowed provider output, or failure must preserve the caller's existing filters and results; never retry as an unrestricted or literal search. Apply a ready filter to list, facet, or map reads and reuse it for paging, history, and view changes. This uses catalog access/read allowances, not Ask questions or research reports.","tags":["Internal canonical queries"],"x-internal":true,"security":[{"AccountCredential":[]}],"x-auth":"Signed Intelligence session or current account credential with catalog access; enabled preview sessions retain their disclosed capabilities and search rate limit. Cookie requests require a session-bound CSRF token and trusted origin.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["kind","text"],"properties":{"kind":{"type":"string","enum":["organization","activity","session"]},"text":{"type":"string","minLength":1,"maxLength":2000,"description":"Trimmed plain-language search; at most 2000 UTF-16 code units. Camp/camps are synonyms for organization/organizations as entity nouns, not name or category constraints; explicit names such as Camp Fire retain their words. The requested kind remains the root scope."}}},"example":{"kind":"organization","text":"Organizations within 10 km of 47.6062, -122.3321"}}}},"responses":{"200":{"description":"A validated best-effort filter, with optional feedback, or a clarification requiring revised search text.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"oneOf":[{"type":"object","additionalProperties":false,"required":["status","kind","filter"],"properties":{"status":{"const":"ready"},"kind":{"type":"string","enum":["organization","activity","session"]},"filter":{"$ref":"#/components/schemas/CanonicalFilter"},"feedback":{"type":"string","minLength":1,"maxLength":2000,"pattern":"\\S","description":"Exceptional note about a material interpretation assumption or approximation that changes expected results, accompanying application of the ready filter without confirmation. Routine defaults, normal interpretation, recaps, and generic caveats stay silent. Nonblank and at most 2000 UTF-16 code units; omitted when there is no important note."}}},{"type":"object","additionalProperties":false,"required":["status","message"],"properties":{"status":{"const":"clarification"},"message":{"type":"string"}}}]}}}}}},"400":{"description":"Missing, repeated, unexpected, or invalid request input."},"401":{"description":"Authentication required."},"403":{"description":"Catalog, preview, or browser CSRF policy refuses this request."},"429":{"description":"Read allowance, preview search rate, or concurrent interpretation limit reached."},"502":{"description":"Provider failed or returned an invalid or disallowed interpretation; preserve existing filters."},"503":{"description":"Search interpretation is not configured."},"504":{"description":"Search interpretation exceeded its deadline; preserve existing filters."}},"x-curl-examples":[{"title":"Translate a coordinate-radius search using an account credential","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/canonical/search/interpret\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"kind\":\"organization\",\"text\":\"Organizations within 10 km of 47.6062, -122.3321\"}'"}]}},"/api/canonical/search":{"get":{"description":"Without mode, retains the canonical search contract: results in organization/activity/session order and an exact total. mode=suggestions ranks one bounded page globally by exact name, prefix, then other name/place matches, with stable folded-name, kind, and UUID ties. Suggestions match names, related camp/activity names, city, and region; descriptions and notes remain in ordinary search only. Suggestions return no total and accept only q, mode, and limit. Query %, _, and ! are literal in suggestions. Each suggestion includes target_kind, id, name, parent_id, parent_name, city, region, verified, and nullable organization_id. The optional location uses only the linked active nonblacklisted organization saved coordinate pair with full stored precision on every plan and finite latitude ±85/longitude ±180 bounds, plus saved coordinate_precision. Missing precision is unknown accuracy. Child coordinates and map centroids never supply camp navigation. Unavailable camps have no organization_id or location. Preview suggestions match fixed disclosed per-kind SQL populations before filters and resolve related names and camp links only inside disclosed organization/activity samples; field masks prevent matching and coordinate disclosure. Ordinary account search without mode retains its existing contract. Preview ordinary search is refused with 403; preview must use mode=suggestions.","parameters":[{"description":"One to five trimmed, deduplicated terms of at most 200 UTF-16 characters each; any term may match.","explode":true,"in":"query","name":"q","required":true,"schema":{"items":{"maxLength":200,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Use suggestions for a bounded global ranking and linked camp location. Omit for ordinary canonical search.","in":"query","name":"mode","schema":{"enum":["suggestions"],"type":"string"}},{"description":"Suggestions: whole number 1–20, default 10. Ordinary search: bounded by the existing 100-result page limit.","in":"query","name":"limit","schema":{"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"oneOf":[{"properties":{"mode":{"const":"suggestions","type":"string"},"preview":{"properties":{"pageSize":{"type":"integer"},"sample":{"type":"boolean"}},"type":"object"},"queries":{"items":{"type":"string"},"type":"array"},"resultLimit":{"type":["integer","null"]},"results":{"items":{"properties":{"city":{"type":["string","null"]},"id":{"format":"uuid","type":"string"},"location":{"properties":{"coordinate_precision":{"enum":["exact","building","parcel","street","zip","state","unknown",null],"type":["string","null"]},"latitude":{"maximum":85,"minimum":-85,"type":"number"},"longitude":{"maximum":180,"minimum":-180,"type":"number"}},"required":["latitude","longitude","coordinate_precision"],"type":"object"},"name":{"type":["string","null"]},"organization_id":{"format":"uuid","type":["string","null"]},"parent_id":{"format":"uuid","type":["string","null"]},"parent_name":{"type":["string","null"]},"region":{"type":["string","null"]},"target_kind":{"enum":["organization","activity","session"],"type":"string"},"verified":{"type":"boolean"}},"type":"object"},"type":"array"},"sourceClass":{"const":"canonical","type":"string"},"tier":{"type":"string"}},"required":["mode","results"],"type":"object"},{"description":"Ordinary account search, with no mode query parameter.","properties":{"queries":{"items":{"type":"string"},"type":"array"},"resultLimit":{"type":"null"},"results":{"items":{"description":"Existing canonical search projection, grouped by organization, activity, then session.","type":"object"},"type":"array"},"sourceClass":{"const":"canonical","type":"string"},"tier":{"type":"string"},"total":{"minimum":0,"type":"integer"}},"required":["results","total"],"type":"object"}]},"success":{"type":"boolean"}},"type":"object"}}},"description":"Successful canonical search."},"400":{"description":"Missing/empty/overlong query, unsupported mode, or malformed suggestions controls."},"401":{"description":"Invalid or missing credentials."},"402":{"description":"Catalog data access requires Starter or above."},"403":{"description":"Preview disclosure is unavailable, or an ordinary preview search was attempted without mode=suggestions."}},"summary":"Search canonical records globally or suggest map navigation targets","tags":["Internal Explorer map"],"x-auth":"Starter or above with current catalog access; preview suggestions require explorer.browse_masked and fixed disclosed samples.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/canonical/search\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"q=wildwood\" \\\n  --data-urlencode \"mode=suggestions\" \\\n  --data-urlencode \"limit=10\"","title":"Suggest map navigation targets"}],"x-internal":true}},"/api/collections":{"get":{"description":"Lists staff-managed collections. archived=false is the default; archived=true selects archived collections, and archived=all includes both. Counts distinguish retained memberships from currently available camps. Collections contain organizations only.","parameters":[{"in":"query","name":"archived","required":false,"schema":{"default":"false","enum":["true","false","all"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"collections":{"items":{"$ref":"#/components/schemas/Collection"},"type":"array"}},"required":["collections"],"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Active or archived shared camp collections with membership counts."},"401":{"description":"Authentication required."},"403":{"description":"Direct staff/ADMIN account required."}},"security":[{"ApiKeyAuth":[]}],"summary":"List shared camp collections","tags":["Collections"],"x-auth":"Direct current staff or ADMIN account session. Service delegation, machine keys, and preview viewers are rejected. Cookie mutations require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/collections\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"archived=true\"","title":"List active and archived collections"}],"x-internal":true},"post":{"description":"Creates a shared staff collection with a case-insensitively unique active name from 1 to 120 characters.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/Collection"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Created shared collection."},"401":{"description":"Authentication required."},"403":{"description":"Direct staff/ADMIN account required."},"404":{"description":"Collection or camp not found."},"409":{"description":"Name conflict or archived collection."}},"security":[{"ApiKeyAuth":[]}],"summary":"Create a camp collection","tags":["Collections"],"x-auth":"Direct current staff or ADMIN account session. Service delegation, machine keys, and preview viewers are rejected. Cookie mutations require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/collections\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Summer research\"}'","title":"Create a shared camp collection"}],"x-internal":true}},"/api/collections/{id}":{"get":{"description":"Reads a collection including archived collections; archived collections preserve membership and remain readable.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/Collection"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Collection metadata and member counts."},"401":{"description":"Authentication required."},"403":{"description":"Direct staff/ADMIN account required."},"404":{"description":"Collection or camp not found."},"409":{"description":"Name conflict or archived collection."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read a camp collection","tags":["Collections"],"x-auth":"Direct current staff or ADMIN account session. Service delegation, machine keys, and preview viewers are rejected. Cookie mutations require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl \"https://apis.schoolsoutapp.com/api/collections/$COLLECTION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read a collection"}],"x-internal":true},"patch":{"description":"Supply name to rename an active collection, or archived=true to archive it. Archived collections cannot be changed or restored.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionUpdateInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/Collection"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Updated collection."},"401":{"description":"Authentication required."},"403":{"description":"Direct staff/ADMIN account required."},"404":{"description":"Collection or camp not found."},"409":{"description":"Name conflict or archived collection."}},"security":[{"ApiKeyAuth":[]}],"summary":"Rename or archive a camp collection","tags":["Collections"],"x-auth":"Direct current staff or ADMIN account session. Service delegation, machine keys, and preview viewers are rejected. Cookie mutations require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl -X PATCH \"https://apis.schoolsoutapp.com/api/collections/$COLLECTION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Summer research 2027\"}'","title":"Rename or archive a collection"}],"x-internal":true}},"/api/collections/{id}/organizations":{"get":{"description":"Returns {organizationIds, unavailableOrganizationIds} from one SQL snapshot. organizationIds contains requested IDs of available camps in the collection. unavailableOrganizationIds contains requested IDs that are missing, deleted, or blacklisted, without distinguishing why. Both arrays omit names. Archived collections are readable. Only absence from organizationIds for an available ID confirms non-membership; an unavailable ID omitted from that array cannot confirm removal.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Comma-separated list of 1–100 distinct organization UUIDs. Inputs are UUID-normalized and deduplicated.","in":"query","name":"organizationIds","required":true,"schema":{"example":"uuid,uuid","maxLength":3699,"minLength":32,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"organizationIds":{"description":"Requested available organization IDs present in the collection.","items":{"format":"uuid","type":"string"},"type":"array"},"unavailableOrganizationIds":{"description":"Requested IDs that are missing, deleted, or blacklisted; the reason is not distinguished.","items":{"format":"uuid","type":"string"},"type":"array"}},"required":["organizationIds","unavailableOrganizationIds"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Requested available member IDs and requested unavailable IDs from one SQL snapshot."},"400":{"description":"Invalid or empty organizationIds list, more than 100 distinct UUIDs, or malformed UUID."},"401":{"description":"Authentication required."},"403":{"description":"Direct staff/ADMIN account required."},"404":{"description":"Collection not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Check camp membership in a collection","tags":["Collections"],"x-auth":"Direct current staff or ADMIN account session. Service delegation, machine keys, and preview viewers are rejected.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/collections/$COLLECTION_ID/organizations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"organizationIds=$CAMP_ID_1,$CAMP_ID_2\"","title":"Check selected camps in one collection"}],"x-internal":true}},"/api/collections/{id}/organizations/{organizationId}":{"delete":{"description":"Removes the organization membership. Repeating the request is idempotent.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"organizationId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"added":{"type":"boolean"},"collectionId":{"format":"uuid","type":"string"},"organizationId":{"format":"uuid","type":"string"},"removed":{"type":"boolean"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Membership result; added or removed is false when membership already had the requested state."},"400":{"description":"Invalid ID or request body."},"401":{"description":"Authentication required."},"403":{"description":"Direct staff/ADMIN account required."},"404":{"description":"Collection or camp not found."},"409":{"description":"Archived collection."}},"security":[{"ApiKeyAuth":[]}],"summary":"Remove a camp from a collection","tags":["Collections"],"x-auth":"Direct current staff or ADMIN account session. Service delegation, machine keys, and preview viewers are rejected. Cookie mutations require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/collections/$COLLECTION_ID/organizations/$CAMP_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Remove a camp from a collection"}],"x-internal":true},"put":{"description":"Adds an available, nondeleted, nonblacklisted organization. Repeating the request is idempotent. Archived collections cannot be changed.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"organizationId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"added":{"type":"boolean"},"collectionId":{"format":"uuid","type":"string"},"organizationId":{"format":"uuid","type":"string"},"removed":{"type":"boolean"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Membership result; added or removed is false when membership already had the requested state."},"400":{"description":"Invalid ID or request body."},"401":{"description":"Authentication required."},"403":{"description":"Direct staff/ADMIN account required."},"404":{"description":"Collection or available camp not found."},"409":{"description":"Archived collection."}},"security":[{"ApiKeyAuth":[]}],"summary":"Add a camp to a collection","tags":["Collections"],"x-auth":"Direct current staff or ADMIN account session. Service delegation, machine keys, and preview viewers are rejected. Cookie mutations require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl -X PUT \"https://apis.schoolsoutapp.com/api/collections/$COLLECTION_ID/organizations/$CAMP_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Add a camp to a collection"}],"x-internal":true}},"/api/health":{"get":{"description":"Returns connected: true when the API can reach its database. It does not expose database or credential details.","responses":{"200":{"content":{"application/json":{"example":{"data":{"connected":true},"success":true}}},"description":"Connection status"}},"security":[],"summary":"Check availability","tags":["System"],"x-auth":"No key required","x-curl-examples":[{"code":"curl \"https://apis.schoolsoutapp.com/api/health\"","title":"Availability"}]}},"/api/ingestion/crawler-jobs":{"get":{"description":"Staff-only list with search, status, page and pageSize filters. Returns data.jobs, total, page and pageSize. Job IDs are decimal strings; counts, depth and masks are integers. Duplicate submissions are independent jobs. Job counts always describe the latest crawl. Failed, blocked or cancelled jobs with an empty latest crawl may include saved_results {attempt_id, attempt_number, counts} for a prior crawl, ranked by retained rows, crawled rows and latest attempt number. Counts come from saved rows, independently of JEV sessions.","responses":{"200":{"description":"Paginated crawler jobs.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["jobs","page","pageSize","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/CrawlerJob"}},"total":{"type":"integer","minimum":0},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","minimum":1}}}}}}}},"400":{"description":"Invalid filters."},"403":{"description":"Staff or ADMIN account required."}},"security":[{"ApiKeyAuth":[]}],"summary":"List crawler jobs","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"status=completed\" \\\n  --data-urlencode \"page=1\" \\\n  --data-urlencode \"pageSize=25\"","title":"List completed crawler jobs"}],"x-internal":true},"post":{"description":"Search mode requires search_term and uses contract 6 when search-domain arrays are empty, or contract 7 when either search_include_domains or search_exclude_domains is nonempty. Both canonical arrays are returned on every job. Organization mode and activity filtering retain contract 5: fetched site evidence, explicit identity/activity assessments and acquisition usage. Acquisition caps are independently nullable; query and candidate caps default to null. Historical contract 3 jobs retain positive integer budgets. Aggregators never qualify. Uncertain results remain unresolved. Gated exports contain only eligible site roots for Trident; URL-only JEV and confidence overrides are rejected. Ordinary search queues provider search followed by optional URL/summary JEV, crawling, and fetched-page evidence JEV. Explicit search domains restrict provider queries and candidate admission before JEV/seed fetch, with exact-host/subdomain matching and exclusions winning. They do not sandbox later crawl discovery or redirects. Canonical page evidence is frozen even without initial JEV; historical contracts 1 through 5 retain URL-only page evaluation. Every request creates a new job. Cookie mutations require CSRF. Credentials belong to workers. At least one active provider bit (1 through 32) is required. Retired provider bits 64 and 128 are rejected for new jobs; historical jobs remain readable.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"acquisition_budget":{"additionalProperties":false,"description":"Optional overrides for gated jobs only. Each member is a positive integer cap or null for no caller cap. Every omitted member defaults to null. Explicit limits are positive signed 32-bit integers. When both are capped, max_pages_per_site must not exceed max_pages.","properties":{"max_candidate_sites":{"default":null,"maximum":2147483647,"minimum":1,"type":["integer","null"]},"max_model_requests":{"default":null,"maximum":2147483647,"minimum":1,"type":["integer","null"]},"max_pages":{"default":null,"maximum":2147483647,"minimum":1,"type":["integer","null"]},"max_pages_per_site":{"default":null,"maximum":2147483647,"minimum":1,"type":["integer","null"]},"max_search_queries":{"default":null,"maximum":2147483647,"minimum":1,"type":["integer","null"]}},"type":"object"},"activity_filter":{"default":false,"description":"Select only first-party sites with fetched activity evidence. New gated jobs use contract 5 and prohibit JEV settings bit 4 and jev_config.","type":"boolean"},"allow_unlimited":{"default":false,"type":"boolean"},"jev_config":{"additionalProperties":false,"properties":{"model":{"default":"jev-1.13.0","type":"string"},"prompt":{"maxLength":16000,"minLength":1,"type":"string"},"settings":{"description":"Only confidence_threshold, batch_size, concurrency, timeout_seconds, max_payload_bytes, max_request_tokens, max_context_tokens and token_buffer_ratio are allowed. batch_size=0 uses adaptive token batching; a positive value adds an item-count ceiling. Token limits apply to state plus all questions and state plus the longest question respectively; token_buffer_ratio reserves headroom in both budgets (default 0.2). confidence_threshold is the minimum yes probability in [0, 1] (default 0.5 for new configurations). No credentials.","type":"object"}},"required":["prompt"],"type":"object"},"max_crawl_depth":{"default":null,"description":"Seed depth is zero. Null or omission means unlimited depth.","maximum":2147483647,"minimum":0,"type":["integer","null"]},"max_urls_per_site":{"default":null,"description":"Unique accepted destinations discovered per source registrable domain across all pages and sitemaps. Null or omission means no caller cap.","maximum":2147483647,"minimum":1,"type":["integer","null"]},"mode":{"default":"search","description":"Organization mode requires organization.name and derives search_term when omitted. It enables activity_filter.","enum":["search","organization_website"],"type":"string"},"organization":{"additionalProperties":false,"properties":{"address":{"maxLength":2000,"type":"string"},"description":{"maxLength":4000,"type":"string"},"email":{"maxLength":2000,"type":"string"},"location":{"maxLength":2000,"type":"string"},"name":{"maxLength":300,"type":"string"},"phone":{"maxLength":2000,"type":"string"},"registration_url":{"maxLength":2000,"type":"string"},"source_url":{"maxLength":2000,"type":"string"},"website_url":{"maxLength":2000,"type":"string"}},"required":["name"],"type":"object"},"provider_mask":{"description":"Google 1, Bing 2, DuckDuckGo 4, Brave 8, Startpage 16, Qwant 32.","maximum":63,"minimum":1,"type":"integer"},"search_exclude_domains":{"description":"Optional bare public DNS names with the same canonical normalization. Exact-host/subdomain exclusions win overlapping includes. Omitted/null/empty means no exclusion; nonempty policy selects contract 7.","items":{"type":"string"},"type":["array","null"]},"search_include_domains":{"description":"Optional bare public DNS names. API normalizes Unicode using nontransitional UTS46 to canonical lowercase ASCII and deduplicates. Omitted/null/empty means unrestricted. Nonempty policy selects contract 7 and is rejected for gated jobs. Restricts provider search and result admission, including subdomains; later crawl/redirect policies remain independent.","items":{"type":"string"},"type":["array","null"]},"search_term":{"maxLength":2000,"minLength":1,"type":"string"},"settings_mask":{"description":"CAPTCHA solving 1, proxies 2, JEV filtering 4, allow external URLs 8. External links are disabled by default; subdomains of the same registrable domain remain eligible.","maximum":15,"minimum":0,"type":"integer"}},"required":["provider_mask","settings_mask"],"type":"object"}}},"required":true},"responses":{"201":{"description":"Independent queued job in data.job.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["job"],"properties":{"job":{"$ref":"#/components/schemas/CrawlerJob"}}}}}}}},"400":{"description":"Invalid fields, flags, depth, or JEV configuration."},"403":{"description":"Staff or ADMIN account required."}},"security":[{"ApiKeyAuth":[]}],"summary":"Create a crawler job","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity. Cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"search_term\":\"summer day camps Seattle\",\"provider_mask\":3,\"settings_mask\":0,\"max_crawl_depth\":2}'","title":"Queue a Google and Bing search crawl two links deep"}],"x-internal":true}},"/api/ingestion/crawler-jobs/stream":{"get":{"description":"Same filters as the job list. Request-based SSE: event:snapshot data is the raw list data projection without a JSON success envelope. Fresh snapshot on every connection, changed snapshots thereafter, and heartbeat comments. Queued job.queue includes state (scheduled, no_active_workers, unavailable_capabilities, workers_busy, ready), message, available_at, active_workers, compatible_workers, ready_workers, bounded workers diagnostics and workers_truncated. Fresh per-worker capabilities are matched together; queue changes stream independently of job.updated_at. Connection lifetime is bounded to renew authorization; reconnect does not restart work. Terminal event:error contains a sanitized message.","responses":{"200":{"content":{"text/event-stream":{"schema":{"type":"string"}}},"description":"SSE snapshots."},"403":{"description":"Staff or ADMIN account required."}},"security":[{"ApiKeyAuth":[]}],"summary":"Stream crawler job list snapshots","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl -N --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/stream\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"status=running\"","title":"Stream running crawler job snapshots"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}":{"get":{"description":"Returns data.job, attempts (including nullable evaluation_id to distinguish re-JEV attempts), bounded meaningful events and results with explicit totals/truncation, optional latest_progress for the current attempt, and evaluations. Exact progress and crawl_progress kinds are excluded from events and its count; unknown kinds are preserved. A queued re-JEV session has no latest_progress. job.latest_event remains the newest raw event. Preview results omit discovery_path; use the paged results endpoint for saved ancestry. Worker artifacts, credentials and page bodies remain private. Job counts always describe the latest crawl. Failed, blocked or cancelled jobs with an empty latest crawl may include saved_results {attempt_id, attempt_number, counts} for a prior crawl, ranked by retained rows, crawled rows and latest attempt number. Counts come from saved rows, independently of JEV sessions. Gated job detail also includes result.site_assessment and job.site_resolution with explicit identity/activity outcomes, evidence, provenance, and acquisition usage.","parameters":[{"in":"path","name":"id","required":true,"schema":{"pattern":"^[1-9][0-9]*$","type":"string"}}],"responses":{"200":{"description":"Crawler detail.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"$ref":"#/components/schemas/CrawlerDetail"}}}}}},"403":{"description":"Staff or ADMIN account required."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read detailed crawler history","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read one crawler job"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/cancel":{"post":{"description":"Stops queued or running crawls with persisted status cancelled and reason Stopped by user. Revokes the active crawl claim and finalizes its original JEV session with already saved URLs. Saved results, judgments and history remain available. Separate re-JEV sessions are unaffected. Already terminal jobs are returned unchanged, including when completion wins a concurrent race. Cookie mutations require CSRF.","parameters":[{"in":"path","name":"id","required":true,"schema":{"pattern":"^[1-9][0-9]*$","type":"string"}}],"responses":{"200":{"description":"Current job in data.job.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["job"],"properties":{"job":{"$ref":"#/components/schemas/CrawlerJob"}}}}}}}},"400":{"description":"Invalid job ID."},"401":{"description":"Authentication required."},"403":{"description":"Staff or ADMIN account and cookie CSRF required."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Stop a crawler job","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity. Cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/cancel\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Stop a queued or running crawl"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/evaluations":{"get":{"description":"Returns data.evaluations, total, page and pageSize. Detail snapshots include the most recent 25 sessions with evaluation_count/evaluations_truncated; this endpoint retrieves earlier preserved sessions. Generic URL-relevance sessions remain unavailable on organization/activity-gated jobs. Trident sessions are available on either job mode; they have purpose trident_summer_camp and kind site_vetting. Only eligible assessments from completed or partial vetting evaluations enter output_urls; unresolved, missing, rejected and unfinished decisions never enter exports. Trident rejects baseline and confidence overrides and preserves source_attempt_id independently of its own attempt_id.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"page","schema":{"minimum":1,"type":"integer"}},{"in":"query","name":"pageSize","schema":{"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"description":"Saved JEV evaluation history.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["evaluations","page","pageSize","total"],"properties":{"evaluations":{"type":"array","items":{"$ref":"#/components/schemas/CrawlerEvaluation"}},"total":{"type":"integer","minimum":0},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","minimum":1}}}}}}}},"403":{"description":"Staff or ADMIN account required."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Page JEV session history","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/evaluations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"page=1\" \\\n  --data-urlencode \"pageSize=25\"","title":"Page earlier JEV sessions"}],"x-internal":true},"post":{"description":"Terminal source job required. Freezes saved crawled final URLs and baseline membership; contract 6 also freezes the complete saved typed page evidence. Missing contract 6 evidence rejects enqueue with 409, and combined URLs/evidence over the request budget reject with 400. No searching, refetching or URL-only fallback occurs. Historical contracts 1 through 5 retain URL-only evaluation. Required jev_config.prompt creates an immutable version. Omitted model, confidence_threshold, concurrency and timeout_seconds inherit the original. New sessions use current defaults for batch_size, max_payload_bytes, max_request_tokens, max_context_tokens and token_buffer_ratio unless explicitly supplied. Optional baseline_evaluation_id must refer to a finalized evaluation from this job. Original results and history remain unchanged. Cookie mutations require CSRF. Generic URL-relevance sessions remain unavailable on organization/activity-gated jobs. Trident sessions are available on either job mode; they have purpose trident_summer_camp and kind site_vetting. Only eligible assessments from completed or partial vetting evaluations enter output_urls; unresolved, missing, rejected and unfinished decisions never enter exports. Trident rejects baseline and confidence overrides and preserves source_attempt_id independently of its own attempt_id.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"baseline_evaluation_id":{"type":"string"},"jev_config":{"properties":{"model":{"type":"string"},"prompt":{"type":"string"},"settings":{"type":"object"}},"required":["prompt"],"type":"object"}},"required":["jev_config"],"type":"object"}}},"required":true},"responses":{"202":{"description":"New queued data.evaluation.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["evaluation"],"properties":{"evaluation":{"$ref":"#/components/schemas/CrawlerEvaluation"}}}}}}}},"400":{"description":"Invalid JEV configuration."},"403":{"description":"Staff or ADMIN account required."},"404":{"description":"Job or baseline not found."},"409":{"description":"Source or baseline is not finalized."}},"security":[{"ApiKeyAuth":[]}],"summary":"Queue a new JEV session","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity. Cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/evaluations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"jev_config\":{\"prompt\":\"Does this page describe a youth summer camp program?\"}}'","title":"Re-judge saved URLs with a new prompt"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/evaluations/{evaluationId}":{"get":{"description":"Returns data.evaluation and data.comparison with added, removed, unchanged, errors, legacy uncertain, pending and output_urls arrays. Counts include decided (yes or no), errors, pending and legacy uncertain outcomes over the canonical candidate total, plus added and removed output URLs against the session's saved baseline (also in history and job detail evaluations). Optional baseline selects a finalized evaluation from the same job. Request errors and pending judgments preserve baseline membership; errors do not add newly included outputs. Generic URL-relevance sessions remain unavailable on organization/activity-gated jobs. Trident sessions are available on either job mode; they have purpose trident_summer_camp and kind site_vetting. Only eligible assessments from completed or partial vetting evaluations enter output_urls; unresolved, missing, rejected and unfinished decisions never enter exports. Trident rejects baseline and confidence overrides and preserves source_attempt_id independently of its own attempt_id.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"evaluationId","required":true,"schema":{"type":"string"}},{"in":"query","name":"baseline","schema":{"type":"string"}}],"responses":{"200":{"description":"Evaluation and comparison.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"$ref":"#/components/schemas/CrawlerEvaluationDetail"}}}}}},"403":{"description":"Staff or ADMIN account required."},"404":{"description":"Evaluation not found in this job."},"409":{"description":"Selected baseline is queued or running."}},"security":[{"ApiKeyAuth":[]}],"summary":"Compare saved JEV outputs","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/evaluations/$EVALUATION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Compare a JEV session with its saved baseline"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/evaluations/{evaluationId}/cancel":{"post":{"description":"Cancels a queued or running rejudge or site_vetting evaluation and its active execution attempt. Original crawl evaluations must be stopped through the source-job cancel route; this endpoint rejects them with 400. Source crawl status, fetched pages and saved partial judgments/assessments remain unchanged. Cancelling a terminal evaluation is idempotent. Worker lease/control fences reject subsequent publication, renewal and completion. Cookie mutations require CSRF.","parameters":[{"in":"path","name":"id","required":true,"schema":{"pattern":"^[1-9][0-9]*$","type":"string"}},{"in":"path","name":"evaluationId","required":true,"schema":{"pattern":"^[1-9][0-9]*$","type":"string"}}],"responses":{"200":{"description":"Current evaluation in data.evaluation.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["evaluation"],"properties":{"evaluation":{"$ref":"#/components/schemas/CrawlerEvaluation"}}}}}}}},"400":{"description":"Invalid ID, unsupported request body, or original crawl evaluation."},"403":{"description":"Staff or ADMIN account and cookie CSRF required."},"404":{"description":"Job or evaluation not found in this job."}},"security":[{"ApiKeyAuth":[]}],"summary":"Stop a saved-URL evaluation","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity. Cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/evaluations/$EVALUATION_ID/cancel\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Stop a saved-URL evaluation"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/export":{"get":{"description":"Downloads distinct sorted included final URLs from saved results only, excluding explicit exclusions and JEV errors. Optional attempt selects an owned crawl attempt; optional evaluation selects a JEV session. These selectors are mutually exclusive. Omission uses the latest crawl attempt. Explicit selection is included in the attachment filename. Optional confidence_threshold selects the same membership as the matching results read. Gated jobs export only evidence-qualified site roots and reject evaluation selection or confidence_threshold with 400.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"evaluation","schema":{"type":"string"}},{"in":"query","name":"attempt","schema":{"pattern":"^[1-9][0-9]*$","type":"string"}},{"description":"Read-time minimum yes confidence. Attempt scope requires a JEV-filtered job; evaluation scope accepts any session.","in":"query","name":"confidence_threshold","schema":{"maximum":1,"minimum":0,"type":"number"}}],"responses":{"200":{"content":{"application/x-ndjson":{"schema":{"type":"string"}}},"description":"URL JSONL attachment."},"400":{"description":"Invalid or conflicting selection, or an invalid confidence_threshold."},"403":{"description":"Staff or ADMIN account required."},"404":{"description":"Job, crawl attempt or evaluation not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Export selected crawler URLs","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/export\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"evaluation=$EVALUATION_ID\" \\\n  --output \"crawler-urls.jsonl\"","title":"Download URLs selected by a JEV session"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/results":{"get":{"description":"Optional attempt selects a saved non-evaluation crawl attempt belonging to this job; omission uses the latest crawl attempt, including empty retries. The response identifies attempt (null before any attempt starts), unfiltered counts for that attempt, and filtered total from one read snapshot. Each result may contain discovery_path: status (complete or partial), root providers, ordered steps (url and via: search, link, redirect, discovery, unknown), and reason. Complete paths begin at a known search provider; partial paths preserve an honest suffix and explain missing ancestry. Absent paths mean the attempt did not save ancestry. Paths have no step-count ceiling and retain a 64 KiB record bound and never require loading a whole-crawl graph or worker filesystem. Decisive yes/no JEV verdicts include nullable yes_probability and no_probability (0-1, both present or both null); a yes below the configuration's confidence_threshold is saved as no with reason yes_confidence_below_threshold. Optional search is a case-insensitive URL substring. Trident evaluation rows also expose site_assessment with grounded evidence, decision and actual homepage/camp entry; membership accepts eligible assessments only after vetting is completed or partial and rejects baseline/confidence overrides. Optional evaluation selects one JEV session of this job instead of a crawl attempt and cannot be combined with attempt or excluded. Its rows are the session's canonical candidate final URLs plus comparison-baseline or output URLs outside them, ordered by depth then URL. Each row adds included (in the session output, the same set as comparison.output_urls and the session export) and baseline_included; excluded is !included. verdict, reason and probabilities come from this session's judgments (null verdict: no judgment for this URL); url, depth, providers, status, fetched_at and discovery_path come from the saved crawl row for that final URL. Optional baseline selects a finished comparison session (default: the session's saved baseline; queued or running is 409). membership (default all) selects included, excluded, or changed (included differs from baseline_included). Evaluation responses contain data.evaluation, baseline_evaluation_id (null means original crawl outputs), unfiltered counts {total, included, excluded, changed, added, removed, errors, pending, uncertain}, results, filtered total, page and pageSize. Optional confidence_threshold re-applies a minimum yes probability to saved decisions without rerunning JEV: a saved model yes (relevant, or no with reason yes_confidence_below_threshold) counts as included only when yes_probability is at least the threshold; model no, decisions without probabilities, uncertain, error and unjudged rows keep their saved membership. It changes membership filters, total, counts (attempt: retained and excluded; evaluation: included, excluded, changed, added, removed) and each row's excluded/included, never the saved verdict, reason or probabilities. In evaluation mode it applies only to the selected session's judgments, never to its baseline URLs or a baseline session, and is accepted for any session, including re-JEV of a crawl without JEV filtering; attempt mode requires a JEV-filtered job. Gated jobs reject evaluation selection and confidence_threshold with 400; gated results are one row per candidate site root with site_assessment evidence and explicit eligibility. site_resolution describes the selected attempt. Optional preview=1 requires a Trident evaluation and membership=all. Before completed/partial final settlement, it adds per-row site_preview (the existing SiteAssessment shape with grounded citations), preview_attempt_id, preview_revision (unique checked-root count as a decimal string), and unfiltered preview_counts {total, checked, eligible, ineligible, uncertain, errors, pending}. The five outcome categories are disjoint and sum to total; unresolved blocked checks are errors, other unresolved checks uncertain, and roots without previews pending. Previews are unpublished and never grant output/export membership. Failed/cancelled previews remain inspectable; queued/new attempts isolate prior previews. Successful settlement omits preview fields and supplies authoritative site_assessment. Legacy workers without typed previews or a qualification progress preview_revision omit preview metadata. The qualification progress revision is scoped to its attempt and triggers a page refresh; the paged response is one consistent snapshot.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"page","schema":{"minimum":1,"type":"integer"}},{"in":"query","name":"pageSize","schema":{"maximum":100,"minimum":1,"type":"integer"}},{"in":"query","name":"search","schema":{"maxLength":2000,"type":"string"}},{"in":"query","name":"excluded","schema":{"type":"boolean"}},{"in":"query","name":"attempt","schema":{"pattern":"^[1-9][0-9]*$","type":"string"}},{"in":"query","name":"evaluation","schema":{"pattern":"^[1-9][0-9]*$","type":"string"}},{"description":"Requires evaluation.","in":"query","name":"baseline","schema":{"pattern":"^[1-9][0-9]*$","type":"string"}},{"description":"Requires evaluation.","in":"query","name":"membership","schema":{"default":"all","enum":["all","included","excluded","changed"],"type":"string"}},{"description":"Read-time minimum yes confidence; same meaning as the JEV setting. Attempt mode requires a JEV-filtered job; evaluation mode accepts any session. Omission keeps saved decisions.","in":"query","name":"confidence_threshold","schema":{"maximum":1,"minimum":0,"type":"number"}},{"description":"Opt-in unpublished per-site Trident inspection; requires evaluation and membership=all.","in":"query","name":"preview","schema":{"enum":["1"],"type":"string"}}],"responses":{"200":{"description":"Attempt mode: data.results, total, page, pageSize, attempt and unfiltered counts. Evaluation mode: data.evaluation, baseline_evaluation_id, counts, results, total, page and pageSize.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"oneOf":[{"$ref":"#/components/schemas/CrawlerResultsPage"},{"$ref":"#/components/schemas/CrawlerEvaluationResultsPage"}]}}}}}},"400":{"description":"Invalid or conflicting selection or filter, including a confidence_threshold that is repeated, not a decimal in [0, 1], or used for attempt results of a job without JEV filtering."},"403":{"description":"Staff or ADMIN account required."},"404":{"description":"Job, attempt, evaluation or baseline not found."},"409":{"description":"Selected comparison baseline is queued or running."}},"security":[{"ApiKeyAuth":[]}],"summary":"Page saved crawler URLs","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/results\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"excluded=false\" \\\n  --data-urlencode \"page=1\" \\\n  --data-urlencode \"pageSize=50\"","title":"Page included URLs from the latest crawl"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/stream":{"get":{"description":"event:snapshot carries raw detail data. Every reconnect starts with current state; stream interruption never cancels work. Queued job.queue uses the same live eligibility projection as the list, including heartbeat staleness transitions without job writes. event:error contains only a sanitized message.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"text/event-stream":{"schema":{"type":"string"}}},"description":"SSE snapshots."},"403":{"description":"Staff or ADMIN account required."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Stream crawler detail snapshots","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl -N --get \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/stream\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Stream one crawler job"}],"x-internal":true}},"/api/ingestion/crawler-jobs/{id}/trident-evaluations":{"post":{"description":"Explicitly queues independent Trident summer-camp vetting. Requires a terminal source crawl/job, including failed or cancelled sources with complete immutable fetched-page evidence. Optional attempt_id selects a source crawl attempt; omission selects the latest terminal crawl. Saves distinct site roots, all frozen pages, purpose, source provenance and a job-scoped idempotency key. Matching retries return the same evaluation; conflicting source reuse returns 409. Performs no new search or fetch. Missing historical evidence requires a recrawl. Cookie mutations require CSRF. Completion and export belong to this evaluation independently of the source crawl status.","parameters":[{"in":"path","name":"id","required":true,"schema":{"pattern":"^[1-9][0-9]*$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"attempt_id":{"pattern":"^[1-9][0-9]*$","type":"string"},"idempotency_key":{"description":"Nonblank key of at most 200 UTF-8 bytes; surrounding whitespace is invalid.","maxLength":200,"minLength":1,"type":"string"}},"required":["idempotency_key"],"type":"object"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"evaluation":{"$ref":"#/components/schemas/CrawlerEvaluation"}},"type":"object"}},"type":"object"}}},"description":"Queued or matching saved evaluation in data.evaluation."},"400":{"description":"Invalid request or unsupported configuration."},"403":{"description":"Staff or ADMIN account and cookie CSRF required."},"404":{"description":"Job not found."},"409":{"description":"Source is active, idempotency conflicts, or saved evidence requires a recrawl."}},"security":[{"ApiKeyAuth":[]}],"summary":"Vet saved websites for their own summer camps","tags":["Internal crawler monitoring"],"x-auth":"Current staff or ADMIN operator identity. Cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-jobs/$CRAWLER_JOB_ID/trident-evaluations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"idempotency_key\":\"trident-vetting-2026-10-10\"}'","title":"Vet the latest terminal crawl for summer camps"}],"x-internal":true}},"/api/ingestion/geocoding/coverage":{"get":{"description":"Counts distinct configurations separately from affected entity references, ZIP coverage, precision, missing coordinates/boundaries, pending/unresolved work, dataset availability, credentials, and worker heartbeat. No provider call. A coverage calculation timeout returns 503 with a retryable message; failed calculations have a retry cooldown.","parameters":[{"description":"Optional US state name/code.","in":"query","name":"state","required":false,"schema":{"type":"string"}},{"description":"Optional recorded city label.","in":"query","name":"city","required":false,"schema":{"type":"string"}},{"description":"Optional US ZIP or ZIP+4.","in":"query","name":"postalCode","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/GeocodingCoverage"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"503":{"description":"Coverage calculation timed out; retry after the calculation cooldown."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read automatic location coverage","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/coverage\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"state=WA\"","title":"Read Washington location coverage as a staff or ADMIN account"}],"x-internal":true}},"/api/ingestion/geocoding/jobs":{"get":{"description":"Paginated job history. Jobs retain their original scope, mode, quote, requester, outcomes, and timestamps.","parameters":[{"description":"Page size (1–100).","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}},{"description":"Zero-based page offset.","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}},{"description":"Optional US state scope filter.","in":"query","name":"state","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"jobs":{"items":{"$ref":"#/components/schemas/GeocodingJob"},"type":"array"},"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"List historical backfill jobs","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/jobs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"state=WA\" \\\n  --data-urlencode \"limit=25\" \\\n  --data-urlencode \"offset=0\"","title":"List the most recent Washington backfill jobs"}],"x-internal":true},"post":{"description":"Recomputes candidate eligibility and pricing transactionally. The fingerprint must match a fresh preview. An idempotency key returns the same job on a repeated confirmation. Freezes candidates and lookup budget; later records enter another job. rerunOf creates a new historical job. Cancellation and uncertain billing do not authorize replacement submissions.","requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/GeocodingPreviewInput"},{"properties":{"fingerprint":{"type":"string"},"idempotencyKey":{"type":"string"}},"required":["fingerprint","idempotencyKey"],"type":"object"}]}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"job":{"$ref":"#/components/schemas/GeocodingJob"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Confirmed job, including repeated idempotent confirmation."},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"409":{"description":"Quote changed or idempotency key conflicts. Obtain a fresh preview before confirming changed work."}},"security":[{"ApiKeyAuth":[]}],"summary":"Confirm a paid backfill","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/jobs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data @geocoding-confirmation.json","title":"Confirm a reviewed paid preview using a JSON file containing its scope, mode, fingerprint, and idempotencyKey"}],"x-internal":true}},"/api/ingestion/geocoding/jobs/{id}":{"get":{"description":"Returns current progress and retained quote/outcomes. Blocked or uncertain provider work is visible.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"job":{"$ref":"#/components/schemas/GeocodingJob"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read one backfill job","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/jobs/$GEOCODING_JOB_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read the job identified by GEOCODING_JOB_ID"}],"x-internal":true}},"/api/ingestion/geocoding/jobs/{id}/cancel":{"post":{"description":"Stops unsent work. Requests already sent retain their outcomes and may settle after cancellation. Does not refund or resend a provider request. Rerun through a new preview and confirmation.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"job":{"$ref":"#/components/schemas/GeocodingJob"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Cancel new backfill submissions","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/jobs/$GEOCODING_JOB_ID/cancel\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Stop new submissions for the job identified by GEOCODING_JOB_ID"}],"x-internal":true}},"/api/ingestion/geocoding/jobs/{id}/items":{"get":{"description":"Returns staff-only configuration address snapshots, item statuses, accepted precision, and exclusion/failure reasons.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Page size (1–500).","in":"query","name":"limit","required":false,"schema":{"maximum":500,"minimum":1,"type":"integer"}},{"description":"Zero-based page offset.","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GeocodingItem"},"type":"array"},"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read backfill item outcomes","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/jobs/$GEOCODING_JOB_ID/items\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"limit=100\" \\\n  --data-urlencode \"offset=0\"","title":"Read the first page of configuration outcomes for a job"}],"x-internal":true}},"/api/ingestion/geocoding/preview":{"post":{"description":"Read-only quote with no Geocodio calls. Shows affected records/configurations, unique/reusable addresses, exclusions, required lookups, and estimated micro-USD cost before shared provider free credits. Excludes explicit non-US and conflicting state/ZIP evidence.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeocodingPreviewInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/GeocodingPreview"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"Preview a paid backfill","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/preview\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"scope\":{\"state\":\"WA\"},\"mode\":\"gaps\"}'","title":"Preview Washington address gaps without calling the paid provider"}],"x-internal":true}},"/api/ingestion/geocoding/regions":{"get":{"description":"Lists supported US states and, when state is supplied, recorded city/ZIP labels and their counts. City labels do not represent polygons.","parameters":[{"description":"Optional state name/code.","in":"query","name":"state","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"cities":{"items":{"properties":{"count":{"type":"integer"},"value":{"type":"string"}},"type":"object"},"type":"array"},"postalCodes":{"items":{"properties":{"count":{"type":"integer"},"value":{"type":"string"}},"type":"object"},"type":"array"},"states":{"items":{"properties":{"code":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"List geocoding scope options","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/regions\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"state=WA\"","title":"List recorded city and ZIP scope options in Washington"}],"x-internal":true}},"/api/ingestion/geocoding/status":{"get":{"description":"Fresh worker heartbeat, credential configuration, and reference availability, independent of the coverage aggregation. Does not scan catalog entities or call a provider.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"reference":{"properties":{"available":{"type":"boolean"},"source":{"type":"string"},"version":{"type":"string"}},"type":"object"},"worker":{"properties":{"error":{"type":"string"},"geocodioConfigured":{"type":"boolean"},"lastSeenAt":{"format":"date-time","type":"string"},"status":{"type":"string"}},"type":"object"}},"required":["worker","reference"],"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Result"},"400":{"description":"Invalid scope, parameters, or missing boundary."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"503":{"description":"Coverage calculation timed out; retry after the calculation cooldown."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read geocoding worker and reference status","tags":["Internal staff geocoding"],"x-auth":"Current staff or ADMIN operator identity. Intelligence uses its signed session cookie; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/geocoding/status\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read geocoding worker and reference status"}],"x-internal":true}},"/api/ingestion/scraper-jobs":{"get":{"description":"Returns paginated durable scraper jobs. Filter by instanceId, case-insensitive website substring (websiteUrl is an alias), exact normalized websiteOrigin or websiteTarget, kind, status, exact failure code (error), and RFC3339 from/to creation bounds. websiteTarget matches all retained jobs for one exact normalized URL across installations; path case and query values stay distinct, while root slash/no-slash aliases share history when their queries match. websiteOrigin matches the scheme and host across page paths and queries; scheme, subdomains, www, and nondefault ports remain distinct. All supplied filters combine. Count and page share a read snapshot ordered by descending creation time then job ID; each page is a fresh read. A nonempty exact target filter is echoed as data.websiteTarget; clients requiring exact history must verify the normalized echo and report unavailable if absent or mismatched. Target history does not establish camp ownership. Unsupported queued work remains visible with its compatibility reason.","parameters":[{"description":"An absolute HTTP(S) URL without credentials, normalized with the queue's URL rules. Path, query, and fragment are ignored; root slashes and default ports normalize.","in":"query","name":"websiteOrigin","schema":{"format":"uri","maxLength":500,"type":"string"}},{"description":"One absolute HTTP(S) URL without credentials, at most 8192 decoded bytes. Queue normalization collapses repeated path slashes, trims non-root trailing slashes, sorts raw query pairs, and removes fragments. Root slash/no-slash aliases share exact history. The applied normalized URL is echoed as data.websiteTarget.","in":"query","name":"websiteTarget","schema":{"format":"uri","maxLength":8192,"type":"string"}},{"description":"An exact job failure code, such as training_mismatch, family_review_required, root_page_missing or crash_loop, at most 1000 characters. Combine with status=failed to list the jobs to retry after a fix.","in":"query","name":"error","schema":{"maxLength":1000,"type":"string"}}],"responses":{"200":{"description":"Paginated scraper jobs.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["jobs","page","pageSize","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/ScraperJob"}},"total":{"type":"integer","minimum":0},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","minimum":1},"websiteTarget":{"type":"string","description":"The normalized website target the list was filtered by, present only when websiteTarget was given."}}}}}}}},"400":{"description":"Invalid filter."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"List scraper jobs","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/scraper-jobs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"websiteOrigin=https://www.example.org\" \\\n  --data-urlencode \"kind=refresh\" \\\n  --data-urlencode \"pageSize=25\"","title":"List refresh jobs for one website origin"}],"x-internal":true},"post":{"description":"Queues onboarding or refresh work for one installation. The API normalizes the URL without probing it, stamps contract version 2 when settings are supplied and version 1 otherwise, and attributes the request to the current operator. Settings are operator overrides for this job only (scope, capture limits, waits, and model budgets); followup refresh and repair jobs inherit them. Unknown or out-of-range settings are rejected. Repeating an identical idempotency key returns the original job; changed input conflicts.","requestBody":{"content":{"application/json":{"schema":{"properties":{"idempotencyKey":{"type":"string"},"instanceId":{"format":"uuid","type":"string"},"kind":{"enum":["onboarding","refresh"]},"settings":{"additionalProperties":false,"properties":{"approved_external_origin":{"description":"An http or https origin captured as the site's one external origin.","format":"uri","type":"string"},"capture_timeout_ms":{"maximum":300000,"minimum":1000,"type":"integer"},"crawl_delay_ms":{"maximum":60000,"minimum":0,"type":"integer"},"dom_quiet_window_ms":{"maximum":30000,"minimum":1,"type":"integer"},"include_subdomains":{"type":"boolean"},"max_corpus_pages":{"maximum":5000,"minimum":1,"type":"integer"},"max_discovery_pages":{"maximum":5000,"minimum":1,"type":"integer"},"max_model_calls":{"maximum":1000,"minimum":1,"type":"integer"},"max_typesafe_requests":{"maximum":1000000,"minimum":1,"type":"integer"}},"type":"object"},"websiteUrl":{"format":"uri","type":"string"}},"required":["instanceId","websiteUrl","kind","idempotencyKey"],"type":"object"}}},"required":true},"responses":{"201":{"description":"Queued job, including an idempotent replay.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["job"],"properties":{"job":{"$ref":"#/components/schemas/ScraperJob"}}}}}}}},"400":{"description":"Invalid submission."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"409":{"description":"Idempotency key conflicts with a different submission."}},"security":[{"ApiKeyAuth":[]}],"summary":"Queue a scraper job","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity. Cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/scraper-jobs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"instanceId\":\"'\"$SCRAPER_INSTANCE_ID\"'\",\"websiteUrl\":\"https://www.example.org/summer\",\"kind\":\"refresh\",\"idempotencyKey\":\"refresh-example-org-2026-10-10\"}'","title":"Queue a website refresh"}],"x-internal":true}},"/api/ingestion/scraper-jobs/website-status":{"get":{"description":"Read-only batch status for exact normalized saved targets. Returns data.websites for each unique target in first-seen order, including never-scraped URLs. Each entry has website and nullable latest, completed and active jobs using the existing sanitized monitoring projection and unsupported-contract reason. Queue normalization lowercases scheme/host, removes default ports, collapses repeated path slashes, trims non-root trailing slashes, sorts raw query pairs and strips fragments. Remaining paths, query values, schemes, host aliases/subdomains and nondefault ports stay distinct. Root slash/no-slash forms share status when their queries match; job.website retains its exact stored value for refresh artifact ownership. Latest/completed use descending creation time then job ID; active prefers running over queued before that order. Invalid or over-limit batches return 400 without truncation. No scraper work is submitted.","parameters":[{"description":"Repeat for 1–50 absolute HTTP(S) URLs without credentials, each at most 8192 decoded bytes. No other query parameters are accepted.","explode":true,"in":"query","name":"websiteUrl","required":true,"schema":{"items":{"format":"uri","type":"string"},"maxItems":50,"minItems":1,"type":"array"},"style":"form"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"websites":{"items":{"properties":{"active":{"type":["object","null"]},"completed":{"type":["object","null"]},"latest":{"type":["object","null"]},"website":{"format":"uri","type":"string"}},"required":["website","latest","completed","active"],"type":"object"},"type":"array"}},"required":["websites"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Exact website statuses."},"400":{"description":"Invalid or over-limit URL batch."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read exact website scrape statuses","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/scraper-jobs/website-status\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"websiteUrl=https://www.example.org/summer\" \\\n  --data-urlencode \"websiteUrl=https://camp.example.org/\"","title":"Read the scrape status of two saved websites"}],"x-internal":true}},"/api/ingestion/scraper-jobs/{id}":{"get":{"description":"Returns a durable job, attempts, sanitized events, linked batch IDs, and downstream website-publication status. Events from contract v3 workers may carry a redacted target URL, bounded redacted detail, model, operation, exit code, and named counters; job lists keep only the event summary. Scrape completion does not imply ingestion completion.","responses":{"200":{"description":"Scraper job detail.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"$ref":"#/components/schemas/ScraperJobDetail"}}}}}},"400":{"description":"Invalid job ID."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read a scraper job","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/scraper-jobs/$SCRAPER_JOB_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read one scraper job"}],"x-internal":true}},"/api/ingestion/scraper-jobs/{id}/retry":{"post":{"description":"Queues a failed job again as a new job on the same installation, with the same website, kind, settings and attempt limit, at the current job contract version, attributed to the current operator. Use it once the fix for the job's failure code is deployed. A failed job has at most one retry: the request returns 201 with the newly queued retry, and 200 with the earlier retry when one exists, whoever asked for it. A retry that fails too is retried by its own ID. The failed job stays unchanged.","responses":{"200":{"description":"The earlier retry of the same failed job; nothing new was queued.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["job"],"properties":{"job":{"$ref":"#/components/schemas/ScraperJob"}}}}}}}},"201":{"description":"The newly queued retry.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["job"],"properties":{"job":{"$ref":"#/components/schemas/ScraperJob"}}}}}}}},"400":{"description":"Invalid job ID."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"404":{"description":"Job not found."},"409":{"description":"The job has not failed."}},"security":[{"ApiKeyAuth":[]}],"summary":"Retry a failed scraper job","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity. Cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/scraper-jobs/$SCRAPER_JOB_ID/retry\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Retry a failed job"}],"x-internal":true}},"/api/ingestion/scraper-jobs/{id}/artifacts":{"get":{"description":"Returns the job's compact diagnostic artifacts, oldest first, with attempt, kind, key, encoded size, and an omission reason (too_large or attempt_budget) instead of a body when one was not stored. Bodies are read one at a time.","responses":{"200":{"description":"Artifact summaries.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["artifacts"],"properties":{"artifacts":{"type":"array","items":{"$ref":"#/components/schemas/ScraperArtifactSummary"}}}}}}}}},"400":{"description":"Invalid job ID."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"404":{"description":"Job not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"List a scraper job's diagnostic artifacts","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/scraper-jobs/$SCRAPER_JOB_ID/artifacts\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List a job’s diagnostic artifacts"}],"x-internal":true}},"/api/ingestion/scraper-jobs/{id}/artifacts/{artifactId}":{"get":{"description":"Returns one artifact of the job with its JSON body. Artifacts may contain page URLs, extracted values, model node selections, generated extractor source, and bounded model output; never captured page bodies, the annotated DOM, or credentials.","responses":{"200":{"description":"Artifact with body.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["artifact"],"properties":{"artifact":{"$ref":"#/components/schemas/ScraperArtifact"}}}}}}}},"400":{"description":"Invalid job or artifact ID."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."},"404":{"description":"Job or artifact not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read a scraper diagnostic artifact","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/scraper-jobs/$SCRAPER_JOB_ID/artifacts/$ARTIFACT_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read one diagnostic artifact body"}],"x-internal":true}},"/api/ingestion/scrapers":{"get":{"description":"Returns scraper installations, current sessions, connection state, every running job (current_jobs, oldest first; current_job is the first), the shared Codex subscription each live session leases (codex_account: id, label, email, or null), each installation's build (revision, and main_revision, behind_main and checked_at as its server last reported them, or null), its newest dashboard update request (update, or null; a request running for over 15 minutes without a result is shown as failed with message no result), and the job-contract revisions accepted by this API process.","responses":{"200":{"description":"Installations and contract compatibility.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["instances","contractVersion","supportedVersions"],"properties":{"instances":{"type":"array","items":{"$ref":"#/components/schemas/ScraperInstance"}},"contractVersion":{"type":"integer"},"supportedVersions":{"type":"array","items":{"type":"integer"}}}}}}}}},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"List scraper installations","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/scrapers\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List scraper installations"}],"x-internal":true}},"/api/ingestion/scrapers/{id}/update":{"post":{"description":"Queues an update to the main revision the installation's server last reported (build.main_revision). The installation's own worker drains its jobs (about 10 minutes at most, otherwise the request is refused as busy), then hands the request to the server's root-owned update script. The script re-validates it (the target must be on a freshly fetched main), runs the new build's database check (refused with the missing migration otherwise), installs it, and rolls back on failure. The next worker records the result: data.request moves through pending, draining and running to succeeded, rolled_back, failed or refused, with from_revision, to_revision, and a redacted message and log_tail. Responses never contain server paths or secrets.","responses":{"202":{"description":"data.request in pending.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"object","additionalProperties":false,"properties":{"request":{"$ref":"#/components/schemas/ScraperUpdateRequest"}},"required":["request"]},"success":{"type":"boolean"}},"required":["data","success"]}}}},"400":{"description":"Invalid ID."},"404":{"description":"Unknown installation."},"409":{"description":"The installation already has an active update request, or its server has not reported the main revision."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"Update a scraper installation to main","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/scrapers/$SCRAPER_INSTALLATION_ID/update\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Update to main"}],"x-internal":true,"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"},"description":"Scraper installation ID."}]}},"/api/ingestion/scrapers/{id}/rollback":{"post":{"description":"Queues a rollback to the installation's previous build; it runs like an update, with target_revision null.","responses":{"202":{"description":"data.request in pending.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"object","additionalProperties":false,"properties":{"request":{"$ref":"#/components/schemas/ScraperUpdateRequest"}},"required":["request"]},"success":{"type":"boolean"}},"required":["data","success"]}}}},"400":{"description":"Invalid ID."},"404":{"description":"Unknown installation."},"409":{"description":"The installation already has an active update request."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"Roll a scraper installation back","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/scrapers/$SCRAPER_INSTALLATION_ID/rollback\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Roll back"}],"x-internal":true,"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"},"description":"Scraper installation ID."}]}},"/api/ingestion/codex-accounts":{"get":{"description":"Returns data.accounts: the team's Codex (ChatGPT) subscriptions that are not removed, with status, the device link and code while a login waits for approval, usage percentages and reset time, the leasing worker, and a redacted last error. Never returns tokens, auth.json contents, or filesystem paths.","responses":{"200":{"description":"The subscription pool.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["accounts"],"properties":{"accounts":{"type":"array","items":{"$ref":"#/components/schemas/ScraperCodexAccount"}}}}}}}}},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"List shared Codex subscriptions","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/ingestion/codex-accounts\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List shared Codex subscriptions"}],"x-internal":true},"post":{"description":"Adds a subscription labelled 1-80 characters (for example the teammate's name) in pending_login. A worker runs codex login --device-auth for it and publishes device_url, user_code and code_expires_at for the teammate to approve.","responses":{"201":{"description":"data.account in pending_login.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["account"],"properties":{"account":{"$ref":"#/components/schemas/ScraperCodexAccount"}}}}}}}},"400":{"description":"Invalid label."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"Add a shared Codex subscription","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl \"https://apis.schoolsoutapp.com/api/ingestion/codex-accounts\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H 'content-type: application/json' \\\n  -d '{\"label\":\"Alex\"}'","title":"Add a subscription"}],"x-internal":true}},"/api/ingestion/codex-accounts/{id}/remove":{"post":{"description":"Marks the subscription removing. The worker holding it (or any worker when none holds it) stops using it, deletes the server's login directory, and marks it removed. It never logs the subscription out or revokes its tokens, so the teammate stays signed in elsewhere.","responses":{"202":{"description":"data.account in removing.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["account"],"properties":{"account":{"$ref":"#/components/schemas/ScraperCodexAccount"}}}}}}}},"400":{"description":"Invalid ID."},"404":{"description":"Unknown or already removed subscription."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"Remove a shared Codex subscription","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/codex-accounts/$CODEX_ACCOUNT_ID/remove\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Remove a subscription"}],"x-internal":true,"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"},"description":"Codex subscription ID."}]}},"/api/ingestion/codex-accounts/{id}/usage-ceiling":{"post":{"description":"Sets usage_ceiling_pct, a whole percent from 1 to 100, or clears it with null. The ceiling applies to the total reported use of either window (five-hour or weekly), including the owner's own use outside Trident. At or above it, workers lease no new calls on the subscription, calls already running finish, and the worker switches to another subscription (or pauses on Codex when none is usable); the subscription keeps its login. It returns once a fresh usage reading after its window resets is below the ceiling, or at once when the ceiling is raised above current use or cleared. Allowed in any status before removal, including before sign-in completes. A small overshoot is possible: readings are at most about a minute old and running calls finish.","responses":{"200":{"description":"data.account with the new usage_ceiling_pct.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","additionalProperties":false,"required":["account"],"properties":{"account":{"$ref":"#/components/schemas/ScraperCodexAccount"}}}}}}}},"400":{"description":"Invalid ID, or usage_ceiling_pct missing, not a whole number from 1 to 100 and not null, or sent with other fields."},"404":{"description":"Unknown or removed subscription."},"401":{"description":"Authentication required."},"403":{"description":"Current identity lacks staff/ADMIN operator access."}},"security":[{"ApiKeyAuth":[]}],"summary":"Set or clear a shared Codex subscription's usage ceiling","tags":["Internal scraper monitoring"],"x-auth":"Current staff or ADMIN operator identity.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/codex-accounts/$CODEX_ACCOUNT_ID/usage-ceiling\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"usage_ceiling_pct\":50}'","title":"Stop using a subscription at 50% of either window"}],"x-internal":true,"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"},"description":"Codex subscription ID."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["usage_ceiling_pct"],"properties":{"usage_ceiling_pct":{"type":["integer","null"],"minimum":1,"maximum":100}}},"example":{"usage_ceiling_pct":50}}}}}},"/api/insights":{"get":{"description":"Lists the datasets your key can access, largest first. Top-level capabilities are the tier-filtered union available across those datasets; each dataset also reports only the exact filters, searchable fields, sortable fields, and dynamic filter that its columns and your plan support. The catalog accepts no query parameters.","responses":{"200":{"content":{"application/json":{"example":{"data":{"capabilities":{"dynamicFilter":"data.<key>","exactFilters":["source","record_type","category","provider","name","state","city","county","country","domain","external_id","parent_external_id","status"],"searchable":["name","provider","category","description","city","county","state","country"],"sortable":["created_at","ingested_at","name","rating","review_count","amount_cents","starts_at","state","city","source"]},"datasetCount":2,"datasets":[{"capabilities":{"dynamicFilter":"data.<key>","exactFilters":["source","record_type","category","provider","name","state","city","county","country","domain","external_id","parent_external_id","status"],"searchable":["name","provider","category","description","city","county","state","country"],"sortable":["created_at","ingested_at","name","rating","review_count","amount_cents","starts_at","state","city","source"]},"dataset":"booking_platform_census","endpoint":"/api/insights/booking_platform_census","rows":26805,"sources":[{"rows":26805,"source":"booking_fingerprint"}]}],"endpoints":{"catalog":"/api/insights","dataset":"/api/insights/{dataset}?q=&{exactFilter}=&data.<key>=&limit=&offset=&orderBy=&order=&format=csv","search":"/api/insights/search?q=&dataset=&{exactFilter}=&limit=&offset="},"tier":"enterprise","totalRows":30970},"success":true}}},"description":"Datasets, row counts, sources, query capabilities, and endpoint paths"},"400":{"content":{"application/json":{"example":{"data":null,"error":true,"message":"The insights catalog does not accept query parameters."}}},"description":"The catalog received a query parameter."},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"List datasets","tags":["Data and insights"],"x-auth":"Administrator account or named integration key owned by an administrator. Legacy Insights data is ADMIN-only; ordinary paid plans do not grant access.","x-curl-examples":[{"code":"curl \"https://apis.schoolsoutapp.com/api/insights\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Catalog"}]}},"/api/insights/search":{"get":{"description":"Searches available text fields across every dataset your key can access, or one dataset selected with dataset. Up to five q values are matched in one ranked request. Exact, prefix, and substring matches are relevance-ranked; ties are ordered by name, dataset, then UUID. Exact filters narrow the results; a cross-dataset search skips datasets without every requested filter. Each non-q parameter may appear once, and unknown, blank, excessive, repeated, or malformed parameters return 400. A busy search service returns 429 with a one-second retry delay.","parameters":[{"description":"One to five required search terms, trimmed and deduplicated before use. Searches the visible fields a dataset carries from: name, provider, category, description, city, county, state, and country. A record may match any term. Matching is case-insensitive. Exact matches rank above prefixes, then other substrings. Earlier fields carry more weight among the searchable fields available on that dataset. Every hit includes a score; higher scores are more relevant. %, _, and ! are matched literally, not treated as pattern syntax.","explode":true,"in":"query","name":"q","required":true,"schema":{"example":["camp fire","robotics"],"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Search only this case-insensitive dataset identifier from GET /api/insights. An unknown dataset returns 404; a dataset unavailable to your plan returns 403.","in":"query","name":"dataset","required":false,"schema":{"example":"atlanta_camps","type":"string"}},{"description":"Rows per page. Must be a whole number from 1 through 200; invalid values return 400. Defaults to 50. Free accounts receive 403: the Data Explorer opens with the Starter plan.","in":"query","name":"limit","required":false,"schema":{"default":50,"maximum":200,"minimum":1,"type":"integer"}},{"description":"Zero-based row offset. Must be a whole number from 0 through 10,000; invalid values return 400. When hasMore is true, use nextOffset for the following page. Free accounts receive 403: the Data Explorer opens with the Starter plan.","in":"query","name":"offset","required":false,"schema":{"default":0,"maximum":10000,"minimum":0,"type":"integer"}},{"description":"Case-sensitive exact source match.","in":"query","name":"source","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact record type match.","in":"query","name":"record_type","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact category match.","in":"query","name":"category","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact provider match. A plan without provider access receives 403.","in":"query","name":"provider","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact name match. q still determines which records are searched and ranked.","in":"query","name":"name","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact state match, usually a two-letter abbreviation.","in":"query","name":"state","required":false,"schema":{"example":"GA","type":"string"}},{"description":"Case-sensitive exact city match.","in":"query","name":"city","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact county match.","in":"query","name":"county","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact country match.","in":"query","name":"country","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact domain match. A plan without business identity access receives 403.","in":"query","name":"domain","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact source-system identifier match.","in":"query","name":"external_id","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact parent source-system identifier match.","in":"query","name":"parent_external_id","required":false,"schema":{"type":"string"}},{"description":"Case-sensitive exact status match.","in":"query","name":"status","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"count":1,"hasMore":true,"hits":[{"category":"Camp","dataset":"atlanta_camps","id":"00000000-0000-0000-0000-000000000000","name":"Atlanta Art Camp","record_type":"provider","score":80,"source":"atlanta_remys"}],"limit":25,"nextOffset":25,"offset":0,"q":"art camp","queries":["art camp"],"tier":"paid"},"success":true}}},"description":"A relevance-ranked page with limit, offset, hasMore, nextOffset, and a score on every hit. Free accounts receive 403: the Data Explorer opens with the Starter plan."},"400":{"$ref":"#/components/responses/InvalidSearchQuery"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/SearchBusy"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"$ref":"#/components/responses/SearchTimeout"}},"summary":"Search datasets","tags":["Data and insights"],"x-auth":"Administrator account or named integration key owned by an administrator. Legacy Insights data is ADMIN-only; ordinary paid plans do not grant access.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/insights/search\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"q=art camp\" \\\n  --data-urlencode \"q=robotics\" \\\n  --data-urlencode \"state=GA\" \\\n  --data-urlencode \"limit=25\" \\\n  --data-urlencode \"offset=0\"","title":"Search and filter every visible dataset"},{"code":"curl --get \"https://apis.schoolsoutapp.com/api/insights/search\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"q=stem\" \\\n  --data-urlencode \"dataset=atlanta_camps\" \\\n  --data-urlencode \"category=Camp\"","title":"Search one dataset"}]}},"/api/insights/{dataset}":{"get":{"description":"Filters and pages one dataset. Each q searches name, and up to five q values are joined with OR in one request. Named filters and data.{key} use case-sensitive exact matches, and multiple filters are joined with AND. Unknown parameters, blank values, malformed controls, too many q values, and repeated format, limit, offset, orderBy, or order parameters return 400.","parameters":[{"description":"A dataset identifier from GET /api/insights, such as atlanta_camps. Identifiers are case-insensitive.","in":"path","name":"dataset","required":true,"schema":{"example":"atlanta_camps","type":"string"}},{"description":"Searches the name column only. Repeat q up to five times to match any term in one request. Matching is case-insensitive and substring-based. It does not search category, provider, location, or data. % matches any sequence and _ matches one character; use cross-dataset search when those characters must be treated literally.","explode":true,"in":"query","name":"q","required":false,"schema":{"example":["art camp","robotics"],"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"An exact, case-sensitive source value. Check /api/insights/{dataset}/facets or the catalog’s sources list for valid values.","in":"query","name":"source","required":false,"schema":{"example":"booking_fingerprint","type":"string"}},{"description":"An exact, case-sensitive record type. Only some datasets include this field.","in":"query","name":"record_type","required":false,"schema":{"type":"string"}},{"description":"An exact, case-sensitive category. This does not accept substrings or a list of values.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"An exact provider value. This filter is available only when your plan includes the provider field.","in":"query","name":"provider","required":false,"schema":{"type":"string"}},{"description":"An exact, case-sensitive name. Use q to search within a name.","in":"query","name":"name","required":false,"schema":{"example":"Camp Wildwood","type":"string"}},{"description":"An exact state value, usually a two-letter abbreviation. Full state names are not converted for you.","in":"query","name":"state","required":false,"schema":{"example":"GA","type":"string"}},{"description":"An exact, case-sensitive city.","in":"query","name":"city","required":false,"schema":{"example":"Atlanta","type":"string"}},{"description":"An exact, case-sensitive county.","in":"query","name":"county","required":false,"schema":{"type":"string"}},{"description":"An exact, case-sensitive country.","in":"query","name":"country","required":false,"schema":{"type":"string"}},{"description":"An exact domain. This filter is available only when your plan includes business identity fields.","in":"query","name":"domain","required":false,"schema":{"example":"example.org","type":"string"}},{"description":"An exact identifier from the source system.","in":"query","name":"external_id","required":false,"schema":{"type":"string"}},{"description":"An exact parent identifier from the source system.","in":"query","name":"parent_external_id","required":false,"schema":{"type":"string"}},{"description":"An exact, case-sensitive status.","in":"query","name":"status","required":false,"schema":{"type":"string"}},{"description":"Matches one top-level data value as exact text. Replace {key} with the JSON key, for example data.facility_type=Day Camp. Keys may contain letters, numbers, underscores, periods, hyphens, and spaces. A key hidden by your plan returns 403.","example":"data.facility_type=Day Camp","in":"query","name":"data.{key}","required":false,"schema":{"type":"string"}},{"description":"Rows per page. Must be a whole number from 1 through 500 for JSON or 1 through 5,000 for CSV; invalid values return 400. Defaults to 50 for JSON and 500 for CSV. Free accounts receive 403: the Data Explorer opens with the Starter plan.","in":"query","name":"limit","required":false,"schema":{"default":50,"example":50,"maximum":5000,"minimum":1,"type":"integer"}},{"description":"Zero-based row offset. Must be a non-negative whole number; invalid values return 400. Free accounts receive 403: the Data Explorer opens with the Starter plan.","in":"query","name":"offset","required":false,"schema":{"default":0,"example":100,"minimum":0,"type":"integer"}},{"description":"Column used for sorting. Must be one of the listed fields and available on the dataset; unsupported values return 400, while a field blocked by your plan returns 403. Defaults to created_at. Nulls sort last.","in":"query","name":"orderBy","required":false,"schema":{"default":"created_at","enum":["created_at","ingested_at","name","rating","review_count","amount_cents","starts_at","state","city","source"],"type":"string"}},{"description":"Sort direction. Accepts asc or desc, without regard to case; any other value returns 400. Defaults to desc.","in":"query","name":"order","required":false,"schema":{"default":"desc","enum":["asc","desc"],"type":"string"}},{"description":"Set to csv, without regard to case, to download one CSV page. Any other value returns 400. CSV uses the same filters, field access, sorting, and offset as JSON, with a 5,000-row maximum page size.","in":"query","name":"format","required":false,"schema":{"enum":["csv"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"count":50,"dataset":"atlanta_camps","hasMore":true,"limit":50,"offset":0,"order":"asc","orderBy":"name","rows":[],"tier":"paid","total":52},"success":true}}},"description":"A page of matching rows, or a CSV download. JSON includes total, count, limit, offset, and hasMore. Free accounts receive 403: the Data Explorer opens with the Starter plan."},"400":{"$ref":"#/components/responses/InvalidDatasetQuery"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Filter a dataset","tags":["Data and insights"],"x-auth":"Administrator account or named integration key owned by an administrator. Legacy Insights data is ADMIN-only; ordinary paid plans do not grant access.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/insights/atlanta_camps\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"q=art camp\"","title":"Name contains words"},{"code":"curl --get \"https://apis.schoolsoutapp.com/api/insights/atlanta_camps\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"q=camp\" \\\n  --data-urlencode \"state=GA\" \\\n  --data-urlencode \"category=STEM\" \\\n  --data-urlencode \"orderBy=name\" \\\n  --data-urlencode \"order=asc\" \\\n  --data-urlencode \"limit=50\"","title":"Combine exact filters with q"},{"code":"curl --get \"https://apis.schoolsoutapp.com/api/insights/national_camp_lists\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"data.facility_type=Day Camp\"","title":"Filter a JSON key"},{"code":"curl --get \"https://apis.schoolsoutapp.com/api/insights/atlanta_camps\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"state=GA\" \\\n  --data-urlencode \"format=csv\" \\\n  -o atlanta-camps.csv","title":"Download the filtered rows"}]}},"/api/insights/{dataset}/facets":{"get":{"description":"Lists common values and row counts for source, record_type, category, provider, status, state, county, city, and country when those fields are visible. The response includes up to 50 values per field. Free accounts receive 403: the Data Explorer opens with the Starter plan. This endpoint accepts no query parameters.","parameters":[{"description":"A dataset slug from GET /api/insights.","in":"path","name":"dataset","required":true,"schema":{"example":"atlanta_camps","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"dataset":"atlanta_camps","facets":{"state":[{"rows":52,"value":"GA"}]},"tier":"paid"},"success":true}}},"description":"Filter values and row counts"},"400":{"$ref":"#/components/responses/NoQueryParameters"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"List filter values","tags":["Data and insights"],"x-auth":"Administrator account or named integration key owned by an administrator. Legacy Insights data is ADMIN-only; ordinary paid plans do not grant access.","x-curl-examples":[{"code":"curl \"https://apis.schoolsoutapp.com/api/insights/atlanta_camps/facets\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Available exact filters"}]}},"/api/insights/{dataset}/{id}":{"get":{"description":"Returns one record by its School’s Out UUID. This endpoint accepts no query parameters.","parameters":[{"description":"A dataset slug from GET /api/insights.","in":"path","name":"dataset","required":true,"schema":{"example":"atlanta_camps","type":"string"}},{"description":"The UUID in the record’s id field. Source-system identifiers do not work here.","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"One record"},"400":{"$ref":"#/components/responses/InvalidRowId"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Get a record","tags":["Data and insights"],"x-auth":"Administrator account or named integration key owned by an administrator. Legacy Insights data is ADMIN-only; ordinary paid plans do not grant access.","x-curl-examples":[{"code":"curl \"https://apis.schoolsoutapp.com/api/insights/atlanta_camps/ROW_UUID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"One row"}]}},"/api/organizations":{"get":{"description":"Filters, sorts, and pages the canonical organization catalog. canonical_url is the verified official primary source. relevant_urls is an array of supporting or unverified pages; inclusion does not establish an official site. Both URL fields require Team data access. JSON rows omit scores and list reads do not load score summaries or calculate scores. minimumScore and maximumScore are inclusive whole-number bounds; score filtering and ordering happen across the complete cohort selected by the ordinary organization filters before pagination. For filtered or score-ordered queries, total is the exact number of matching organizations. Unfiltered total and unfilteredTotal use durable incrementally maintained totals after relevant background work settles and fall back to live counts while committed changes are pending. Returned rows and access checks remain live. Score filters, counts, and ordering use persisted results refreshed by workers after evidence changes and roughly hourly for time-based decay. Pausing workers retains cached scores and their evaluation times without preventing API reads. The separate cached score batch endpoint reads the same persisted results; calculatedAt reports their stored evaluation time. Reads do not load score evidence or evaluate decay. Organization rows without prepared scores remain visible unless excluded by a score filter or score ordering. Returns retryable 503 until score objects are installed. To count scores strictly above 80, send minimumScore=81 and limit=1. ageYears uses whole completed years. The legacy ageMonths filter remains available; month-shaped aliases derived from canonical inclusive year bounds use [yearMin*12,yearMax*12+11]. collectionId is staff-only; collections contain organizations and do not infer activity or session category labels. Each ordinary JSON row includes image_urls, a deduplicated array of its own active image URLs, ordered by selected cover, selected logo where applicable, then gallery position. Empty galleries return an empty array. Remote URLs are preserved verbatim; uploaded images retain protected organization brand-asset URLs. Documents, deleted or misowned uploads, inactive memberships, other entities’ media, and source provenance are excluded. Investor previews omit image_urls, CSV columns remain unchanged, and includeRows=false skips media reads. Normal JSON records omit bookkeeping and ingestion history, null and blank record fields, and unknown availability, registration-status, and coordinate-precision values. Zero, false, empty arrays, masked values, positional range bounds, and structured schedule states retain their meanings. Related entity summaries follow the same projection; CSV and SQL retain their existing contracts. Bookkeeping and provenance are available separately at /api/organizations/{id}/provenance. Age ranges use age_range_years; normal JSON records and column metadata omit the redundant age_range_months alias. CSV, SQL, and the legacy ageMonths filter retain month compatibility. Records and column metadata omit score. Read /api/organizations/{id}/score for live detail or /api/organizations/scores?ids=UUID,UUID&cached=true for persisted summaries. The structured filter JSON combines with legacy parameters using AND. All branches validate against current field disclosure; see CanonicalFilter and /api/canonical/schema. Ordinary permitted JSON records include resolved_cover with the ultimate source entity, inheritance flag, and structured stock attribution. Owned gallery and image compatibility fields retain their existing meaning.","parameters":[{"description":"Case-insensitive substring search across organization name, description, city, region, and age keyword. Repeat up to five times to match any term.","explode":true,"in":"query","name":"q","required":false,"schema":{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":5,"minItems":1,"type":"array"},"style":"form"},{"description":"Case-insensitive exact city name or its lowercase hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Case-insensitive exact region, such as a state abbreviation.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on the organization itself; categories are independent across organizations, activities, and sessions.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Returns organizations whose stated grade range includes this grade. Use -1 for pre-K and 0 for kindergarten.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Sort by score, name, city, region, created_at, or updated_at. Without orderBy, the catalog uses updated_at descending.","in":"query","name":"orderBy","required":false,"schema":{"enum":["score","name","city","region","created_at","updated_at"],"type":"string"}},{"description":"Sort direction. An explicit orderBy uses ascending order when this is omitted.","in":"query","name":"order","required":false,"schema":{"enum":["asc","desc"],"type":"string"}},{"description":"One-based page number.","in":"query","name":"page","required":false,"schema":{"default":1,"minimum":1,"type":"integer"}},{"description":"Set false to return counts and metadata with an empty organizations array. Cannot be combined with format=csv.","in":"query","name":"includeRows","required":false,"schema":{"default":true,"type":"boolean"}},{"description":"Page size from 1 to 100 for JSON.","in":"query","name":"limit","required":false,"schema":{"default":24,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Requires a direct staff or ADMIN account; service delegation, machine keys, and previews are refused. Filters organizations by one shared camp collection; map routes include coherently owned descendants.","in":"query","name":"collectionId","required":false,"schema":{"format":"uuid","type":"string"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON predicate tree, sent once. Combines with all legacy filters using AND before rows, totals and facet counts are selected. Read /api/canonical/schema tables[*].filterCapabilities for visible fields, operators, relations and limits. Invalid/unknown/over-complex filters return 400; unavailable fields return 403, including in nonmatching branches. Do not broaden a failed request by dropping predicates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}}],"responses":{"200":{"content":{"application/json":{"example":{"data":{"limit":1,"order":"desc","orderBy":"updated_at","organizations":[{"city":"Seattle","id":"00000000-0000-0000-0000-000000000000","name":"Camp Wildwood","region":"WA","image_urls":["https://images.example.com/camp-wildwood/cover.jpg","https://images.example.com/camp-wildwood/logo.png"]}],"page":1,"pageCount":143,"tier":"paid","total":143},"success":true}}},"description":"A tier-masked page. total reflects every ordinary and score filter before pagination. Records omit scores; use the separate score endpoints when needed."},"400":{"content":{"application/json":{"example":{"data":null,"error":true,"message":"Query parameter \"minimumScore\" must be a whole number between 0 and 100."}}},"description":"A score bound is not a whole number from 0 through 100, minimumScore exceeds maximumScore, or q is invalid. Also returned for malformed, repeated, unsupported, over-complex, or incorrectly typed filter JSON."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"500":{"$ref":"#/components/responses/ServerError"},"403":{"description":"A filter names a field or relation outside the current plan or preview disclosure."}},"summary":"Query organizations","tags":["Organization catalog"],"x-auth":"Account or named integration API key on Starter or above. The response fields are masked to the owner’s current plan.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"minimumScore=81\" \\\n  --data-urlencode \"limit=1\"","title":"Count organizations scoring above 80"},{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"region=WA\" \\\n  --data-urlencode \"minimumScore=80\" \\\n  --data-urlencode \"orderBy=score\" \\\n  --data-urlencode \"order=desc\" \\\n  --data-urlencode \"limit=25\"","title":"List the highest-scoring organizations in Washington"}]}},"/api/organizations/facets":{"get":{"description":"Counts under the canonical list filters and current field access. A single-field request with snapshot=true and no search or filters reads durable incrementally maintained counts after relevant background work settles. While committed edits, deletion, blacklisting, or calendar expiry work is pending, the request falls back to live counts; failed refreshes leave that fallback active. Filtered requests and the default stay live. collectionId is staff-only; collections contain organizations and do not infer activity or session category labels. Organization category facets read each organization’s own categories; they do not aggregate activity labels. The same structured filter JSON and legacy list filters narrow the population using AND before aggregation. Structured filters always use live counts. q searches facet values; search carries the list text search. All filter branches enforce current field disclosure.","parameters":[{"description":"Facet field.","in":"query","name":"field","schema":{"enum":["city","region","category","updated_day"],"type":"string"}},{"description":"Use the stored unfiltered chart distribution. Must be exactly true or false.","in":"query","name":"snapshot","schema":{"default":false,"type":"boolean"}},{"in":"query","name":"limit","schema":{"default":30,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Filter records before aggregation; uses live counts.","in":"query","name":"search","schema":{"type":"string"}},{"description":"Search facet values; uses live counts.","in":"query","name":"q","schema":{"type":"string"}},{"description":"Requires a direct staff or ADMIN account; service delegation, machine keys, and previews are refused. Filters organizations by one shared camp collection; map routes include coherently owned descendants.","in":"query","name":"collectionId","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"Returns organizations whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Case-insensitive exact city name or its lowercase hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Case-insensitive exact region, such as a state abbreviation.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on the organization itself; categories are independent across organizations, activities, and sessions.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Returns organizations whose stated grade range includes this grade. Use -1 for pre-K and 0 for kindergarten.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON predicate tree, sent once. Combines with all legacy filters using AND before rows, totals and facet counts are selected. Read /api/canonical/schema tables[*].filterCapabilities for visible fields, operators, relations and limits. Invalid/unknown/over-complex filters return 400; unavailable fields return 403, including in nonmatching branches. Do not broaden a failed request by dropping predicates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}}],"responses":{"200":{"description":"Existing success envelope containing facets, tier, resultLimit, and sourceClass. A single field returns values with value, label, and rows."},"400":{"description":"Invalid field or snapshot option. Also returned for malformed, repeated, unknown, over-complex or incorrectly typed structured filter JSON."},"401":{"description":"Authentication required."},"402":{"description":"Starter or higher required."},"403":{"description":"A structured filter names a field or relationship outside current tier or preview disclosure."}},"summary":"Read organizations facet or chart counts","tags":["Canonical"],"x-auth":"Account or named integration API key on Starter or above. Facet fields follow the owner’s current plan.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations/facets\" -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" --data-urlencode \"field=region\" --data-urlencode \"snapshot=true\"","title":"Read organizations chart counts"}]}},"/api/organizations/{id}":{"get":{"description":"Returns one tier-masked canonical organization and its Activity summaries without loading or calculating scores. Deprecated includeScore=false is accepted as a no-op; includeScore=true returns 400 directing callers to /api/organizations/{id}/score. Repeated or malformed includeScore values return 400. Normal JSON records omit bookkeeping and ingestion history, null and blank record fields, and unknown availability, registration-status, and coordinate-precision values. Zero, false, empty arrays, masked values, positional range bounds, and structured schedule states retain their meanings. Related entity summaries follow the same projection; CSV and SQL retain their existing contracts. Moved fields are configuration_id, external_ids, created_at, updated_at, source_created_at, field_provenance, source_records, merge_jobs, and relationship_jobs. Read permitted bookkeeping and provenance at /api/organizations/{id}/provenance. Age ranges use age_range_years; normal JSON records and column metadata omit the redundant age_range_months alias. CSV, SQL, and the legacy ageMonths filter retain month compatibility. Records and column metadata omit score. Read /api/organizations/{id}/score for live detail or /api/organizations/scores?ids=UUID,UUID&cached=true for persisted summaries. Normal detail responses include data.media, the first gallery page of up to 100 images, with entity, items, coverId, logoId, total, limit, and offset. Images include displayUrl, label, kind, width, and height; source attribution is omitted even for ADMIN. Previews omit media. Optional includeMedia=false skips the gallery; omitted or true includes it. The parameter accepts one exact true or false value, with malformed or repeated values returning 400. Use the existing /media endpoint for additional pages or authorized source attribution. On /media, includeProvenance=false skips source attribution; omitted or true retains existing authority-gated sources. Use limit=1 at the selected image offset when requesting only its source history. Ordinary permitted JSON records include resolved_cover with the ultimate source entity, inheritance flag, and structured stock attribution. Owned gallery and image compatibility fields retain their existing meaning.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Deprecated no-op accepting false only. Omit this parameter; scores are read from /api/organizations/{id}/score. true, malformed, and repeated values return 400.","in":"query","name":"includeScore","schema":{"type":"boolean","enum":[false]},"deprecated":true},{"name":"includeMedia","in":"query","required":false,"description":"One exact true or false value. Omitted or true bundles the first gallery page; false skips media for follow-up diagnostic reads. Previews always omit media.","schema":{"type":"boolean","default":true}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"organization":{"$ref":"#/components/schemas/CanonicalDetailRow"},"media":{"$ref":"#/components/schemas/CanonicalMediaPage"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Canonical organization detail"},"404":{"$ref":"#/components/responses/NotFound"},"400":{"description":"includeScore=true, malformed/repeated includeScore, or invalid detail parameters. Malformed or repeated includeMedia also returns 400."}},"summary":"Read one canonical organization","tags":["Organization catalog"],"x-auth":"Account cookie or header, or permitted machine key, from Starter up. Active organization members receive their existing organization detail access.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations/$ORGANIZATION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read one organization"}]}},"/api/organizations/{id}/media":{"get":{"description":"Returns this record’s owned paginated gallery and selections plus resolvedCover for display. Inherited covers retain their owning record and do not change gallery membership or counts. Stock covers include public provider and photographer credits. Remote URLs and R2 URLs are served directly; uploaded assets retain protected URLs. Source evidence is available only to non-preview ADMIN accounts. Pagination uses the existing catalog bounds.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Defaults to 30 when absent or invalid; values over 100 cap at 100.","in":"query","name":"limit","schema":{"default":30,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Defaults to 0 when absent or invalid; values over 1000000 cap at 1000000.","in":"query","name":"offset","schema":{"default":0,"maximum":1000000,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/CanonicalMediaPage"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Paginated media and selected IDs"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Starter access is required."},"403":{"description":"Previews cannot read media."},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Read organization media","tags":["Organization catalog"],"x-auth":"Starter or above, or an active member of the requested organization; previews are denied. Resolved covers follow the same media access gates.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations/$ORGANIZATION_ID/media\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"limit=30\" \\\n  --data-urlencode \"offset=0\"","title":"Read the first page of an organization gallery"}]}},"/api/organizations/{id}/update-form":{"post":{"description":"Saves attributed, reversible organization edits. Omitted and blank/null fields are ignored. clearFields explicitly clears editable non-required fields; required fields such as name cannot be cleared. A clear or replacement of a populated, different value requires reason; filling a missing value or confirming the same value does not. sourceURL is an optional HTTP(S) citation for submitted field values. Human edits outrank automated contributions, including human-approved Overseer proposals; source freshness applies within one authority. Adds supporting links from organization.relevant_urls and removes explicitly selected supporting links from removeRelevantUrls. Both use HTTP(S) form normalization. Unspecified and concurrently added URLs remain; removal wins over a simultaneous addition. Removing the last link is allowed. Duplicate additions and absent removals record no new ownership. The official canonical_url is separate. Changes retain attributed, reversible contribution history; later removals remain authoritative during undo. Public update-token forms reject removeRelevantUrls and clearFields for relevant_urls; supporting links remain add-only there.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"assets":{"items":{"type":"object"},"type":"array"},"brand":{"type":"object"},"clearFields":{"description":"Names of editable fields to clear. Cannot include required fields or a field also present in organization. For relevant_urls, this clears all supporting links; use removeRelevantUrls to remove selected links.","items":{"type":"string"},"type":"array"},"organization":{"description":"Omitted and blank/null fields are ignored. relevant_urls is an additive HTTP(S) array or newline-separated list.","type":"object"},"reason":{"description":"Human rationale required for every clear or replacement of a populated, different value; optional for fills and same-value confirmations.","maxLength":2000,"type":"string"},"removeRelevantUrls":{"description":"Explicit supporting links to remove using form URL normalization. Unspecified URLs remain; removal wins over simultaneous addition. A nonempty list permits removal-only saves.","items":{"format":"uri","type":"string"},"type":"array"},"sourceURL":{"description":"Optional absolute HTTP(S) citation without credentials for submitted field values.","format":"uri","maxLength":2000,"type":"string"},"submitter":{"type":"object"}},"type":"object"}}},"required":true},"responses":{"200":{"description":"Saved organization, changedFields, submittedFields, batchId and brand. Clear operations and conflicting replacements require a human reason; no effective URL change creates no URL contribution."},"400":{"description":"Invalid edit or URL list."},"401":{"description":"Authentication required."},"403":{"description":"No camp edit permission."},"404":{"description":"Camp not found."}},"security":[{"AccountCredential":[]}],"summary":"Save attributed camp field edits","tags":["Internal organization editing"],"x-auth":"Current ADMIN/staff account or active organization member. Machine keys do not inherit membership; cookie POST requests require CSRF.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/organizations/$ORGANIZATION_ID/update-form\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"organization\":{\"relevant_urls\":[\"https://www.example.org/summer-camps\"]},\"removeRelevantUrls\":[\"https://www.example.org/old-camp-page\"]}'","title":"Add one supporting link and remove another"}],"x-internal":true}},"/api/overseer":{"get":{"description":"Reads or replaces the shared Overseer instructions and tool controls. Structured saves supply directives and optionally disabledTools with expectedRevision. Each edit atomically creates a revision, fences previous execution, and cancels its undelivered one-off messages; committed child jobs remain. Empty or all-disabled instructions idle the worker unless a one-off message, requested correction, or system revalidation is pending. Global pause still prevents execution. Legacy directive text is supported: saving its unchanged projection preserves structured instructions, while changed text replaces them with one enabled item; omitted disabledTools preserves restrictions. Stale expectedRevision returns 409 and the current snapshot. executionActive reports a current unexpired worker lease, not worker health. Native thread IDs, checkpoints and execution tokens remain private. latestSlackDelivery is a safe durable observation, not a claim about current channel configuration. paused and pauseVersion expose a global control independent of instruction revision. Configuration saves never implicitly resume paused execution.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Current directive and safe progress projection."},"401":{"description":"Authentication required."},"403":{"description":"Current identity is not a user-backed staff or ADMIN operator, or the browser mutation lacks a trusted origin and session-bound CSRF token."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read Overseer instructions, tools and progress","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN identity. Account credentials and machine keys belonging to eligible users are accepted; a bare service credential is not. Intelligence uses its signed session cookie; cookie PUT requests require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/overseer\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read the directive and current progress"}],"x-internal":true},"put":{"description":"Reads or replaces the shared Overseer instructions and tool controls. Structured saves supply directives and optionally disabledTools with expectedRevision. Each edit atomically creates a revision, fences previous execution, and cancels its undelivered one-off messages; committed child jobs remain. Empty or all-disabled instructions idle the worker unless a one-off message, requested correction, or system revalidation is pending. Global pause still prevents execution. Legacy directive text is supported: saving its unchanged projection preserves structured instructions, while changed text replaces them with one enabled item; omitted disabledTools preserves restrictions. Stale expectedRevision returns 409 and the current snapshot. executionActive reports a current unexpired worker lease, not worker health. Native thread IDs, checkpoints and execution tokens remain private. latestSlackDelivery is a safe durable observation, not a claim about current channel configuration. paused and pauseVersion expose a global control independent of instruction revision. Configuration saves never implicitly resume paused execution.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"directive":{"description":"At most 65536 UTF-8 bytes. Empty or whitespace-only text idles the runner.","type":"string"},"expectedRevision":{"description":"Revision returned by the last snapshot the caller reviewed.","minimum":0,"type":"integer"},"directives":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/OverseerDirective"}},"disabledTools":{"type":"array","uniqueItems":true,"items":{"type":"string"},"description":"Disabled names from availableTools. Mandatory history, review reconciliation and lifecycle tools cannot be disabled."}},"required":["expectedRevision"],"type":"object","oneOf":[{"required":["directive"],"not":{"required":["directives"]}},{"required":["directives"],"not":{"required":["directive"]}}]}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Saved directive at its new revision."},"400":{"description":"Invalid directive or expected revision, or unsupported input field."},"401":{"description":"Authentication required."},"403":{"description":"Current identity is not a user-backed staff or ADMIN operator, or the browser mutation lacks a trusted origin and session-bound CSRF token."},"409":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"error":{"const":true},"message":{"type":"string"},"success":{"const":false}},"required":["data","success","message"],"type":"object"}}},"description":"The directive changed. Preserve the local draft and review the current snapshot before retrying."}},"security":[{"ApiKeyAuth":[]}],"summary":"Save Overseer instructions and tool controls","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN identity. Account credentials and machine keys belonging to eligible users are accepted; a bare service credential is not. Intelligence uses its signed session cookie; cookie PUT requests require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"title":"Save enabled and disabled instructions","code":"curl -X PUT \"https://apis.schoolsoutapp.com/api/overseer\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"directives\":[{\"id\":\"washington\",\"text\":\"Verify Washington camp schedules.\",\"enabled\":true}],\"disabledTools\":[\"start_crawler\"],\"expectedRevision\":12}'"}],"x-internal":true}},"/api/overseer/clear-memory":{"post":{"description":"Clears the current execution memory while retaining the exact saved directive and report cadence. It preserves the directive revision, revokes the current run, and emits a memory_cleared event when a saved revision exists. The next execution starts with a fresh native thread and no prior checkpoint or narrative. Historical jobs, action receipts, audit events, and minimal action references remain for provenance and to avoid duplicate actions. A blank or absent directive is allowed; requested corrections and system revalidation remain actionable. Review history and suppression are preserved. A stale expectedRevision returns 409 with the current public snapshot. Thread IDs, checkpoints, and execution authority remain private. Structured instruction enablement and tool restrictions remain unchanged. Undelivered one-off requests are cancelled with message_cancelled events. The global pause state and its version are preserved.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"expectedRevision":{"description":"Revision returned by the snapshot the operator reviewed.","minimum":0,"type":"integer"}},"required":["expectedRevision"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Existing directive revision with cleared conversation memory."},"400":{"description":"Missing, invalid, or unsupported request input."},"401":{"description":"Authentication required."},"403":{"description":"Current identity is not a user-backed staff or ADMIN operator, or the browser mutation lacks a trusted origin and session-bound CSRF token."},"409":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"error":{"const":true},"message":{"type":"string"},"success":{"const":false}},"required":["data","success","message"],"type":"object"}}},"description":"The directive changed. Review the current snapshot before clearing memory again."}},"security":[{"ApiKeyAuth":[]}],"summary":"Clear Overseer conversation memory","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN identity. Account credentials and machine keys belonging to eligible users are accepted; a bare service credential is not. Intelligence uses its signed session cookie; cookie POST requests require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/overseer/clear-memory\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"expectedRevision\":12}'","title":"Clear memory for the directive reviewed at revision 12"}],"x-internal":true}},"/api/overseer/events":{"get":{"description":"Reads bounded Overseer history. Default order=asc uses the exclusive afterId cursor and returns nextAfterId. order=desc uses exclusive beforeId and returns nextBeforeId; omit the cursor for the newest page. Both return events in the requested order and hasMore, preserve an empty page cursor, accept optional revision (0 means all), and limit 1 to 200. Wrong-direction, mixed, duplicate, unsupported and invalid query parameters return 400. Only directive_saved events include a top-level directive loaded from that durable revision, including empty text for idle; other events omit it. Organization links in details.links include a display label resolved from the current camp name, including historical events. Unnamed or unavailable camps receive an identifying fallback containing the preserved camp ID. Labels do not change stored audit records or action receipts. Completed assistant messages use kind=agent_output with details.text, source (coordinator or subagent), phase (commentary or final_answer), optional ordinal agentLabel, and truncated. Text preserves line breaks after credential redaction and byte bounds. Coordinator final control documents, reasoning, tool payloads and native identities are excluded. These observations do not replace verified progress or directive state; existing history pagination applies.","parameters":[{"description":"Default asc. Desc reads newest events first.","in":"query","name":"order","schema":{"enum":["asc","desc"],"type":"string"}},{"description":"Exclusive ascending cursor. Rejected when order=desc.","in":"query","name":"afterId","schema":{"minimum":0,"type":"integer"}},{"description":"Exclusive descending cursor. Only accepted with order=desc; omit or use 0 for the newest page.","in":"query","name":"beforeId","schema":{"minimum":0,"type":"integer"}},{"description":"Optional exact revision; omitted or 0 includes all revisions.","in":"query","name":"revision","schema":{"minimum":0,"type":"integer"}},{"description":"Maximum events returned, default 100.","in":"query","name":"limit","schema":{"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"oneOf":[{"not":{"required":["nextBeforeId"]},"required":["nextAfterId"]},{"not":{"required":["nextAfterId"]},"required":["nextBeforeId"]}],"properties":{"events":{"items":{"$ref":"#/components/schemas/OverseerEvent"},"type":"array"},"hasMore":{"type":"boolean"},"nextAfterId":{"description":"Present for default/asc order; use as the next afterId.","minimum":0,"type":"integer"},"nextBeforeId":{"description":"Present only for order=desc; use as the next beforeId.","minimum":0,"type":"integer"}},"required":["events","hasMore"],"type":"object"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Events in ascending ID order and their next cursor."},"400":{"description":"Unsupported, duplicate, malformed or out-of-range query parameter."},"401":{"description":"Authentication required."},"403":{"description":"Current identity is not a user-backed staff or ADMIN operator, or the browser mutation lacks a trusted origin and session-bound CSRF token."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read Overseer audit events","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN identity. Account credentials and machine keys belonging to eligible users are accepted; a bare service credential is not. Intelligence uses its signed session cookie; cookie PUT requests require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/overseer/events\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"order=desc\" \\\n  --data-urlencode \"limit=50\"","title":"Read the newest audit events"}],"x-internal":true}},"/api/overseer/evidence/{id}":{"get":{"description":"Returns original captured pixels while retained. The global newest 10000 Overseer images are kept; metadata survives removal. Removed images return HTTP 410 and are never recreated by replay.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"image/png":{"schema":{"format":"binary","type":"string"}}},"description":"Captured source PNG.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"description":"Invalid or unsupported input."},"401":{"description":"Authentication required."},"403":{"description":"Current operator access and, for cookie decisions, trusted origin and session-bound CSRF are required."},"404":{"description":"Review or source capture not found."},"410":{"description":"Image bytes are no longer retained; capture metadata remains available."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read immutable research source pixels","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN operator; account credentials or eligible machine keys, or the signed Intelligence cookie. Cookie decisions require a trusted origin and session-bound CSRF token. Bare service credentials and preview viewers are rejected.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/overseer/evidence/$EVIDENCE_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --output \"overseer-evidence.png\"","title":"Download one source capture"}],"x-internal":true}},"/api/overseer/jobs":{"get":{"description":"Reads current crawler/scraper queue status for explicit durable Overseer action links across revisions. Jobs are deduplicated by kind and ID and attributed to their first linked action revision. Newest first uses an opaque exclusive before cursor and returns jobs, nextBefore and hasMore; limit is 1 to 200, and optional revision selects the originating revision. Later references do not move a job or change its origin. label is the crawl search term or scraper website. campId is nonnull only for one explicit organization link on the originating action that resolves to a live camp; no website/name match or inferred followup establishes a relationship. Missing jobs and other link kinds are omitted. Raw action inputs, results, evidence and execution authority are never returned.","parameters":[{"description":"Opaque exclusive cursor from nextBefore. Omit for newest linked jobs.","in":"query","name":"before","schema":{"type":"string"}},{"description":"Optional originating revision; omitted or 0 includes all revisions.","in":"query","name":"revision","schema":{"minimum":0,"type":"integer"}},{"description":"Maximum jobs returned, default 100.","in":"query","name":"limit","schema":{"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"hasMore":{"type":"boolean"},"jobs":{"items":{"$ref":"#/components/schemas/OverseerLinkedJob"},"type":"array"},"nextBefore":{"type":["string","null"]}},"required":["jobs","nextBefore","hasMore"],"type":"object"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Linked jobs, current queue status and stable backward cursor."},"400":{"description":"Malformed cursor, unsupported or duplicate query, or out-of-range limit/revision."},"401":{"description":"Authentication required."},"403":{"description":"Current user-backed staff/ADMIN operator required; preview denied."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read linked Overseer jobs","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN identity. Account credentials and machine keys belonging to eligible users are accepted; a bare service credential is not. Intelligence uses its signed session cookie; cookie PUT requests require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/overseer/jobs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --data-urlencode \"limit=50\"","title":"Read the newest linked jobs"}],"x-internal":true}},"/api/overseer/review-groups":{"get":{"description":"Reads retained update versions across all instruction revisions. Application and optional review status are independent. Filters and stable cursor pagination select history without granting mutation authority. Evidence images are served separately through the authenticated evidence endpoint.","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["applied","not_applied","revalidation_requested","reverting","reverted","revert_failed","all"]}},{"in":"query","name":"auditStatus","schema":{"type":"string","enum":["unreviewed","reviewed","changes_requested","all"]}},{"in":"query","name":"organizationId","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"q","schema":{"type":"string","maxLength":200}},{"in":"query","name":"afterId","schema":{"type":"string","maxLength":512}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50,"default":25}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerReviewGroupsPage"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Paged update history."},"400":{"description":"Invalid or unsupported input."},"401":{"description":"Authentication required."},"403":{"description":"Current operator access is required."}},"security":[{"ApiKeyAuth":[]}],"summary":"Group update history by business","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN operator; account credentials or eligible machine keys, or the signed Intelligence cookie. Bare service credentials and preview viewers are rejected.","x-curl-examples":[{"title":"Read unreviewed updates","code":"curl --get \"https://apis.schoolsoutapp.com/api/overseer/review-groups\" -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" --data-urlencode \"auditStatus=unreviewed\" --data-urlencode \"limit=25\""}],"x-internal":true}},"/api/overseer/reviews":{"get":{"description":"Reads every saved update version across all instruction revisions. Application and optional review status are independent. Paired entityKind and entityId select one exact record, excluding child records. retainedOnly=true selects versions applied at least once that reference a screenshot whose image remains retained, including later reverted versions. Partially expired versions preserve all evidence references and unavailable capture metadata. With either a record or retention scope, counts cover every matching version before pagination; other requests retain global history counts. Cursors bind all filters. Evidence images are served separately through the authenticated evidence endpoint.","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["applied","not_applied","revalidation_requested","reverting","reverted","revert_failed","all"]}},{"in":"query","name":"auditStatus","schema":{"type":"string","enum":["unreviewed","reviewed","changes_requested","all"]}},{"in":"query","name":"organizationId","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"entityKind","description":"Exact record kind. Must be supplied together with entityId; excludes child records.","schema":{"type":"string","enum":["organization","activity","session"]}},{"in":"query","name":"entityId","description":"Exact canonical record UUID. Must be supplied together with entityKind.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"retainedOnly","description":"Only versions with appliedAt and at least one referenced evidence capture whose screenshot image remains retained. Later reversal does not remove a version; partially expired evidence remains visible.","schema":{"type":"boolean","default":false}},{"in":"query","name":"q","schema":{"type":"string","maxLength":200}},{"in":"query","name":"afterId","schema":{"type":"string","maxLength":512}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50,"default":25}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerReviewPage"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Paged update history."},"400":{"description":"Invalid or unsupported input."},"401":{"description":"Authentication required."},"403":{"description":"Current operator access and, for cookie decisions, trusted origin and session-bound CSRF are required."},"404":{"description":"Review or source capture not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Read update history","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN operator; account credentials or eligible machine keys, or the signed Intelligence cookie. Cookie decisions require a trusted origin and session-bound CSRF token. Bare service credentials and preview viewers are rejected.","x-curl-examples":[{"title":"Read unreviewed updates","code":"curl --get \"https://apis.schoolsoutapp.com/api/overseer/reviews\" -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" --data-urlencode \"auditStatus=unreviewed\" --data-urlencode \"limit=25\""}],"x-internal":true}},"/api/overseer/reviews/{id}":{"get":{"description":"Returns one immutable update version, actual application receipt, baseline and applied values, current canonical context, source evidence metadata, and optional review feedback. Historical versions remain independently addressable after later updates.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"version","schema":{"type":"integer","minimum":1},"description":"Read this exact retained update version. Omitted selects the latest."}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerReviewDetail"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Review and full-record comparison."},"400":{"description":"Invalid or unsupported input."},"401":{"description":"Authentication required."},"403":{"description":"Current operator access and, for cookie decisions, trusted origin and session-bound CSRF are required."},"404":{"description":"Review or source capture not found."}},"security":[{"ApiKeyAuth":[]}],"summary":"Inspect an update version and source evidence","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN operator; account credentials or eligible machine keys, or the signed Intelligence cookie. Cookie decisions require a trusted origin and session-bound CSRF token. Bare service credentials and preview viewers are rejected.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/overseer/reviews/$REVIEW_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Inspect one review"}],"x-internal":true}},"/api/overseer/reviews/{id}/decision":{"post":{"description":"Targets the exact expectedVersion. Mark reviewed changes audit state only. Request changes targets the latest version, leaves its contribution live, and wakes the existing Overseer worker for a fresh correction. Revert queues the version contribution batch through the existing reversal worker and suppresses further automatic updates for the record until request_changes explicitly reopens it. A queued reversal is reverting, not completed. Request IDs bind the exact normalized body; identical replay recovers its durable receipt or definitive rejection without executing again. Screenshot expiry does not block these actions. Current staff account authority and cookie CSRF remain required.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverseerReviewDecisionInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerReview"},"success":{"const":true}},"required":["success","data"],"type":"object"}}},"description":"Recorded decision and resulting review."},"400":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/OverseerRejectedReviewDecision"},{"not":{"required":["decisionOutcome"]},"properties":{"data":{"type":"null"},"error":{"const":true},"message":{"type":"string"}},"type":"object"}]}}},"description":"Invalid input; a committed rejection of a well-formed decision additionally returns its requestId and decisionOutcome=rejected. Validation before persistence has no terminal marker."},"401":{"description":"Authentication required."},"403":{"description":"Current human account operator access is required; privileged machine keys and service-delegated accounts are denied. Cookie decisions also require a trusted origin and session-bound CSRF token."},"404":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/OverseerRejectedReviewDecision"},{"not":{"required":["decisionOutcome"]},"properties":{"data":{"type":"null"},"error":{"const":true},"message":{"type":"string"}},"type":"object"}]}}},"description":"Review or referenced record is missing. A committed rejection receipt includes requestId and decisionOutcome=rejected; an unmarked missing-record response does not resolve an earlier uncertain request."},"409":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/OverseerRejectedReviewDecision"},{"not":{"required":["decisionOutcome"]},"properties":{"data":{"type":"null"},"error":{"const":true},"message":{"type":"string"}},"type":"object"}]}}},"description":"Conflicting review or canonical values. Only a committed rejection receipt carries requestId and decisionOutcome=rejected; reuse of a request ID with different input returns an ordinary conflict without that marker."}},"security":[{"ApiKeyAuth":[]}],"summary":"Review, request changes, or revert an applied update","tags":["Internal Overseer"],"x-auth":"Current staff or ADMIN human account using an account credential or the signed Intelligence cookie. Cookie decisions require a trusted origin and session-bound CSRF token. Machine credentials, service delegation, bare service credentials and preview viewers cannot make review decisions.","x-curl-examples":[{"title":"Request a correction while keeping the current update live","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/overseer/reviews/$REVIEW_ID/decision\" -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" -H \"Content-Type: application/json\" --data '{\"expectedVersion\":3,\"requestId\":\"00000000-0000-4000-8000-000000000001\",\"action\":\"request_changes\",\"feedback\":\"Check the current schedule.\"}'"}],"x-internal":true}},"/api/sessions/facets":{"get":{"description":"Returns canonical session category, city, and registration-status facets under list filters and current field access. Categories are recorded on the session itself and are not inherited from its activity or organization. A single-field request with snapshot=true and no search or filters reads durable incrementally maintained counts after relevant background work settles. While committed edits, deletion, blacklisting, or calendar expiry work is pending, the request falls back to live counts; failed refreshes leave that fallback active. Filtered requests and the default stay live. The same structured filter JSON and legacy list filters narrow the population using AND before aggregation. Structured filters always use live counts. q searches facet values; search carries the list text search. All filter branches enforce current field disclosure.","parameters":[{"description":"Facet field; required when snapshot=true.","in":"query","name":"field","schema":{"enum":["category","city","registration_status","start_week","updated_day"],"type":"string"}},{"description":"Use the stored unfiltered chart distribution. Must be exactly true or false.","in":"query","name":"snapshot","schema":{"default":false,"type":"boolean"}},{"in":"query","name":"limit","schema":{"default":30,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Filter records before aggregation; uses live counts.","in":"query","name":"search","schema":{"type":"string"}},{"description":"Search facet values; uses live counts.","in":"query","name":"q","schema":{"type":"string"}},{"description":"Case-insensitive exact city name or its lowercase hyphenated slug.","in":"query","name":"city","required":false,"schema":{"example":"seattle","type":"string"}},{"description":"Case-insensitive exact region, such as a state abbreviation.","in":"query","name":"region","required":false,"schema":{"example":"WA","type":"string"}},{"description":"Exact category recorded on this session; no parent inheritance.","in":"query","name":"category","required":false,"schema":{"example":"STEM","type":"string"}},{"description":"Returns records whose stated whole completed age range in inclusive age_range_years bounds includes this age in years.","in":"query","name":"ageYears","required":false,"schema":{"example":10,"maximum":8333,"minimum":0,"type":"integer"}},{"description":"Legacy compatibility filter for month-based ages. New clients should use whole-year ageYears; when a whole-year range is sent through a legacy month-shaped adapter, inclusive bounds expand as [yearMin*12,yearMax*12+11].","in":"query","name":"ageMonths","required":false,"schema":{"example":120,"minimum":0,"type":"integer"}},{"description":"Returns records whose stated grade range includes this grade. Use -1 for pre-K and 0 for kindergarten.","in":"query","name":"grade","required":false,"schema":{"example":5,"maximum":12,"minimum":-1,"type":"integer"}},{"description":"Inclusive minimum School’s Out score from the persisted ranking snapshot.","in":"query","name":"minimumScore","required":false,"schema":{"example":81,"maximum":100,"minimum":0,"type":"integer"}},{"description":"Inclusive maximum School’s Out score from the persisted ranking snapshot. It must not be below minimumScore.","in":"query","name":"maximumScore","required":false,"schema":{"example":100,"maximum":100,"minimum":0,"type":"integer"}},{"name":"filter","in":"query","required":false,"description":"One URL-encoded JSON predicate tree, sent once. Combines with all legacy filters using AND before rows, totals and facet counts are selected. Read /api/canonical/schema tables[*].filterCapabilities for visible fields, operators, relations and limits. Invalid/unknown/over-complex filters return 400; unavailable fields return 403, including in nonmatching branches. Do not broaden a failed request by dropping predicates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanonicalFilter"}}}},{"name":"organizationId","in":"query","required":false,"description":"Exact organization UUID. Retained legacy membership filter accepts the session direct organization or its activity organization. Use a related organization predicate for direct-owner-first semantics.","schema":{"type":"string","format":"uuid"}},{"name":"activityId","in":"query","required":false,"description":"Exact session activity UUID.","schema":{"type":"string","format":"uuid"}},{"name":"registrationStatus","in":"query","required":false,"description":"Exact recorded registration_status when visible at the current plan.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Legacy inclusive lower date bound. Explicit attendance and weekly rules honor exclusions; source date ranges retain their broad overlap meaning. Use schedule for exact attendance/windows.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Legacy inclusive upper date bound. Explicit attendance and weekly rules honor exclusions; source date ranges retain their broad overlap meaning. Use schedule for exact attendance/windows.","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Existing success envelope containing facets, tier, resultLimit, and sourceClass. A single field returns values with value, label, and rows."},"400":{"description":"Invalid field or snapshot option. Also returned for malformed, repeated, unknown, over-complex or incorrectly typed structured filter JSON."},"401":{"description":"Authentication required."},"402":{"description":"Starter or higher required."},"403":{"description":"A structured filter names a field or relationship outside current tier or preview disclosure."}},"summary":"Read sessions facet or chart counts","tags":["Canonical"],"x-auth":"Account or named integration API key on Starter or above. Facet fields follow the owner’s current plan.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/sessions/facets\" -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" --data-urlencode \"field=city\" --data-urlencode \"snapshot=true\"","title":"Read sessions chart counts"}]}},"/api/sessions/{id}":{"get":{"description":"Returns the tier-masked session and parent summaries. Sessions own registration_open_date, registration_close_date, and ordered `prices` entries with nullable `price`, `basis`, and `currency`; an entry cannot be all null, `[]` means no recorded price, and zero means explicitly free. Nullable `discounts` holds freeform terms without changing prices or the early-bird flag. Care quotes have independent amount, currency and basis. Pricing remains tier-masked, including nested schedule quotes. schedule_configurations owns session dates and clocks. Each group selects explicit dates, a bounded weekly date_rule with source-stated weekdays and exclusions, or a sole date_range for independently known bounds without known attendance dates. time_kind distinguishes daily, arrival_departure, and unspecified clocks. Effective attendance dates cannot overlap; rules remain rules in responses and ranges never imply attendance. Public scalar dates and clocks are derived read-only summaries. Clearing the collection leaves the schedule unknown. Normal JSON records omit bookkeeping and ingestion history, null and blank record fields, and unknown availability, registration-status, and coordinate-precision values. Zero, false, empty arrays, masked values, positional range bounds, and structured schedule states retain their meanings. Related entity summaries follow the same projection; CSV and SQL retain their existing contracts. Moved fields are configuration_id, external_ids, created_at, updated_at, source_created_at, field_provenance, source_records, merge_jobs, and relationship_jobs. Read permitted bookkeeping and provenance at /api/sessions/{id}/provenance. Age ranges use age_range_years; normal JSON records and column metadata omit the redundant age_range_months alias. CSV, SQL, and the legacy ageMonths filter retain month compatibility. Records and column metadata omit score. Read /api/sessions/{id}/score for live detail or /api/sessions/scores?ids=UUID,UUID&cached=true for persisted summaries. Normal detail responses include data.media, the first gallery page of up to 100 images, with entity, items, coverId, logoId, total, limit, and offset. Images include displayUrl, label, kind, width, and height; source attribution is omitted even for ADMIN. Previews omit media. Optional includeMedia=false skips the gallery; omitted or true includes it. The parameter accepts one exact true or false value, with malformed or repeated values returning 400. Use the existing /media endpoint for additional pages or authorized source attribution. On /media, includeProvenance=false skips source attribution; omitted or true retains existing authority-gated sources. Use limit=1 at the selected image offset when requesting only its source history. The record's independent overnight boolean is true for explicit overnight status and false for explicit day status; unknown or mixed status is omitted. It never inherits a parent's status. Ordinary permitted JSON records include resolved_cover with the ultimate source entity, inheritance flag, and structured stock attribution. Owned gallery and image compatibility fields retain their existing meaning.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"name":"includeMedia","in":"query","required":false,"description":"One exact true or false value. Omitted or true bundles the first gallery page; false skips media for follow-up diagnostic reads. Previews always omit media.","schema":{"type":"boolean","default":true}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"session":{"$ref":"#/components/schemas/CanonicalDetailRow"},"media":{"$ref":"#/components/schemas/CanonicalMediaPage"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Canonical session detail"},"404":{"$ref":"#/components/responses/NotFound"},"400":{"description":"Invalid detail parameters, including malformed or repeated includeMedia."}},"summary":"Read one canonical session","tags":["Organization catalog"],"x-auth":"Account cookie or header, or permitted machine key, from Starter up.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/sessions/$SESSION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read one session"}]}},"/api/sessions/{id}/media":{"get":{"description":"Returns this record’s owned paginated gallery and selections plus resolvedCover for display. Inherited covers retain their owning record and do not change gallery membership or counts. Stock covers include public provider and photographer credits. Remote URLs and R2 URLs are served directly; uploaded assets retain protected URLs. Source evidence is available only to non-preview ADMIN accounts. Pagination uses the existing catalog bounds.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Defaults to 30 when absent or invalid; values over 100 cap at 100.","in":"query","name":"limit","schema":{"default":30,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Defaults to 0 when absent or invalid; values over 1000000 cap at 1000000.","in":"query","name":"offset","schema":{"default":0,"maximum":1000000,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/CanonicalMediaPage"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Paginated media and selected IDs"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Starter access is required."},"403":{"description":"Previews cannot read media."},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Read session media","tags":["Organization catalog"],"x-auth":"Starter or above; previews are denied. Resolved covers follow the same media access gates.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/sessions/$SESSION_ID/media\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"limit=30\" \\\n  --data-urlencode \"offset=0\"","title":"Read the first page of a session gallery"}]}},"/api/users/authenticate-interstitial":{"post":{"description":"Creates a 30-minute one-time code for the signed-in account. REDIRECT_SCHOOLS_OUT_INTELLIGENCE returns INTELLIGENCE_ORIGIN/auth-callback and accepts an optional challenge. REDIRECT_SCHOOLS_OUT_APP returns APP_AUTH_CALLBACK (default schoolsout://auth-callback) and requires a challenge, stored on the code. Outside production the app may pass callback exp://<host>:<port>/--/auth-callback for Expo Go; alternate callbacks are rejected in production; an omitted callback or the exact configured APP_AUTH_CALLBACK is accepted. Accounts without a verified email receive 403 unless they are ADMIN or staff.","requestBody":{"content":{"application/json":{"schema":{"properties":{"callback":{"description":"Optional exact configured APP_AUTH_CALLBACK. Outside production only, exp://<host>:<port>/--/auth-callback is also accepted.","type":"string"},"challenge":{"description":"Unpadded base64url SHA-256 of the client's verifier. Required for REDIRECT_SCHOOLS_OUT_APP.","maxLength":43,"minLength":43,"pattern":"^[A-Za-z0-9_-]{43}$","type":"string"},"domain":{"enum":["REDIRECT_SCHOOLS_OUT_INTELLIGENCE","REDIRECT_SCHOOLS_OUT_APP"],"type":"string"}},"required":["domain"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"code":{"format":"uuid","type":"string"},"existing":{"const":true,"type":"boolean"},"redirectUrl":{"type":"string"}},"required":["code","existing","redirectUrl"],"type":"object"}}},"description":"Code issued"},"400":{"description":"Unknown redirect id, invalid or missing challenge, or a rejected callback"},"401":{"description":"Current account required"},"403":{"description":"Verified email required"}},"security":[{"AccountCredential":[]}],"summary":"Issue a one-time code for a product callback","tags":["Internal sign-in handoff"],"x-auth":"Current account credential or signed session cookie.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/authenticate-interstitial\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"domain\":\"REDIRECT_SCHOOLS_OUT_APP\",\"challenge\":\"BASE64URL_SHA256_OF_VERIFIER\"}'","title":"Issue an app sign-in code"}],"x-internal":true}},"/api/users/exchange-interstitial":{"post":{"description":"Consumes the code once, within 30 minutes of issue, and returns the identity plus sessionKey, the account credential the product keeps server-side or in device secure storage. A code issued with a challenge also requires verifier, and base64url(SHA-256(verifier)) must equal the challenge. Every attempt consumes the code, so a missing or wrong verifier cannot be retried.","requestBody":{"content":{"application/json":{"schema":{"properties":{"code":{"format":"uuid","type":"string"},"verifier":{"type":"string"}},"required":["code"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"sessionKey":{"type":"string"},"user":{"properties":{"email":{"type":["string","null"]},"id":{"type":"string"},"level":{"type":"integer"},"username":{"type":["string","null"]}},"type":"object"}},"required":["sessionKey","user"],"type":"object"}}},"description":"Session issued"},"400":{"description":"Invalid, expired, reused or unproven code"},"401":{"description":"Account unavailable or no longer verified"}},"security":[],"summary":"Exchange a one-time code for the account session","tags":["Internal sign-in handoff"],"x-auth":"Public; the one-time code and, for the app, its verifier are the credentials.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/exchange-interstitial\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"code\":\"TEMPORARY_ACCESS_CODE\",\"verifier\":\"APP_PROOF_VERIFIER\"}'","title":"Exchange an app sign-in code"}],"x-internal":true}},"/api/users/magic-link":{"post":{"description":"Always answers success for a well-formed address. intent (signin|signup) only changes the email copy. redirect, domain and challenge are stored as the link's handoff and returned when POST /api/users/authenticate-code redeems it, so a link requested by the app finishes through the interstitial with the same challenge. domain REDIRECT_SCHOOLS_OUT_APP requires a challenge. The link always opens AUTH_ORIGIN.","requestBody":{"content":{"application/json":{"schema":{"properties":{"challenge":{"description":"Unpadded base64url SHA-256 of the client's verifier. Required for REDIRECT_SCHOOLS_OUT_APP.","maxLength":43,"minLength":43,"pattern":"^[A-Za-z0-9_-]{43}$","type":"string"},"domain":{"type":"string"},"email":{"format":"email","type":"string"},"intent":{"enum":["signin","signup"],"type":"string"},"redirect":{"maxLength":2048,"type":"string"}},"required":["email"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"success":{"const":true,"type":"boolean"}},"required":["success"],"type":"object"}}},"description":"Link sent (or silently skipped)"},"400":{"description":"Invalid email, intent or challenge, or an app link without a challenge"},"429":{"description":"Address or client rate limit"}},"security":[],"summary":"Email a one-shot sign-in link","tags":["Internal sign-in handoff"],"x-auth":"Public.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/magic-link\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"you@example.com\",\"intent\":\"signin\",\"domain\":\"REDIRECT_SCHOOLS_OUT_APP\",\"challenge\":\"BASE64URL_SHA256_OF_VERIFIER\"}'","title":"Email an app sign-in link"}],"x-internal":true}},"/api/users/viewer/care-requirements":{"get":{"description":"Returns every saved requirement, including expired ones, with only the children the adult can currently access. Requirements are private to their owner even for shared children.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"careRequirements":{"items":{"$ref":"#/components/schemas/FamilyCareRequirement"},"type":"array"}},"required":["careRequirements"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"401":{"description":"Current account required"}},"security":[{"AccountCredential":[]}],"summary":"List the signed-in adult's dated care requirements","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/care-requirements\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List care requirements"}],"x-internal":true},"post":{"description":"Saves dates or a date range, required weekdays and local hours, time zone, alternate-week recurrence, exceptions, flexibility, coverage and optional budget/travel overrides for one to ten children the adult can access (owner or current guardian), up to 50 per account. Child access is locked and rechecked so a concurrent revocation is observed. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyCareRequirementInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"careRequirement":{"$ref":"#/components/schemas/FamilyCareRequirement"}},"required":["careRequirement"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Save a dated care requirement for selected children","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/care-requirements\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"childIds\":[\"$CHILD_ID\"],\"label\":\"Summer coverage\",\"dates\":{\"start\":\"2027-06-21\",\"end\":\"2027-08-27\"},\"days\":[\"mon\",\"tue\",\"wed\",\"thu\",\"fri\"],\"hours\":{\"start\":\"08:30\",\"end\":\"17:30\"},\"flexibility\":{\"level\":\"fixed\"},\"coverage\":{\"mode\":\"every_required_day\"}}'","title":"Save summer weekday coverage"}],"x-internal":true}},"/api/users/viewer/care-requirements/{requirementId}":{"delete":{"description":"DELETE {version} removes the requirement and its child links. Stale versions return 409.","parameters":[{"in":"path","name":"requirementId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"version":{"minimum":1,"type":"integer"}},"required":["version"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"deleted":{"const":true}},"required":["deleted"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Remove a care requirement","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/users/viewer/care-requirements/$REQUIREMENT_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":2}'","title":"Remove a care requirement"}],"x-internal":true},"patch":{"description":"Replaces named keys (childIds, label, dates, timezone, days, hours, recurrence, exceptions, flexibility, coverage, budget, travel); null removes an optional key. The merged requirement is validated completely and needs at least one currently permitted child. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","parameters":[{"in":"path","name":"requirementId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyCorrection"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"careRequirement":{"$ref":"#/components/schemas/FamilyCareRequirement"}},"required":["careRequirement"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Correct named parts of a care requirement","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X PATCH \"https://apis.schoolsoutapp.com/api/users/viewer/care-requirements/$REQUIREMENT_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":1,\"changes\":{\"exceptions\":[{\"date\":\"2027-07-05\",\"needed\":false}]}}'","title":"Add a date without care needed"}],"x-internal":true}},"/api/users/viewer/care-requirements/{requirementId}/confirmations":{"post":{"description":"Records a fresh approval of named parts (children, label, dates, timezone, schedule, flexibility, coverage, budget, travel). The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","parameters":[{"in":"path","name":"requirementId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyReconfirmation"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"careRequirement":{"$ref":"#/components/schemas/FamilyCareRequirement"}},"required":["careRequirement"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Reconfirm an unchanged care requirement","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/care-requirements/$REQUIREMENT_ID/confirmations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":2,\"keys\":[\"schedule\"]}'","title":"Reconfirm the schedule"}],"x-internal":true}},"/api/users/viewer/child-invitations/accept":{"post":{"description":"Current nondelegated account with a live verified email matching the invitation recipient. Wrong or unverified accounts receive 403 without child details; unavailable tokens return 404. POST {token,approve:true} consumes an available invitation once and grants guardian access in one transaction. The actor’s current email and verification state are locked, then the profile and invitation are locked and expiry/revocation rechecked. Returns data.child with role guardian. Guardians may read and correct current details/preferences and use owner-enabled registration reuse; they cannot delete the profile, change reuse permission, or manage other guardians. Profile or owner removal cascades invitations and memberships.","requestBody":{"content":{"application/json":{"schema":{"properties":{"approve":{"const":true,"type":"boolean"},"token":{"maxLength":43,"minLength":43,"pattern":"^[A-Za-z0-9_-]{43}$","type":"string"}},"required":["token","approve"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"child":{"$ref":"#/components/schemas/FamilyChildProfile"}},"required":["child"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid invitation input or missing explicit approval"},"401":{"description":"Current account required"},"403":{"description":"Owner-only action or current verified recipient email required"},"404":{"description":"Profile, guardian or invitation not available to this account"},"409":{"description":"Duplicate pending invitation or guardian limit"},"429":{"description":"Invitation creation rate limit"}},"security":[{"AccountCredential":[]}],"summary":"Explicitly accept guardian access once","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/child-invitations/accept\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Explicitly accept guardian access once"}],"x-internal":true}},"/api/users/viewer/child-invitations/preview":{"post":{"description":"Current nondelegated account with a live verified email matching the invitation recipient. Wrong or unverified accounts receive 403 without child details; unavailable tokens return 404. POST {token} returns the child name, inviting owner email, recipient address and invitation dates for review. It does not return saved profile fields or grant access. Tokens travel in the JSON body, not the API URL. Invitation landing links use /family/invitations#token.","requestBody":{"content":{"application/json":{"schema":{"properties":{"token":{"maxLength":43,"minLength":43,"pattern":"^[A-Za-z0-9_-]{43}$","type":"string"}},"required":["token"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"invitation":{"$ref":"#/components/schemas/ChildInvitationPreview"}},"required":["invitation"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid invitation input or missing explicit approval"},"401":{"description":"Current account required"},"403":{"description":"Owner-only action or current verified recipient email required"},"404":{"description":"Profile, guardian or invitation not available to this account"},"409":{"description":"Duplicate pending invitation or guardian limit"},"429":{"description":"Invitation creation rate limit"}},"security":[{"AccountCredential":[]}],"summary":"Review an invitation addressed to your verified email","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/child-invitations/preview\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Review an invitation addressed to your verified email"}],"x-internal":true}},"/api/users/viewer/children":{"get":{"description":"Current account cookie or account credential only; machine keys and delegated service requests are rejected. Lists owned child profiles and profiles with an accepted, active guardian membership, with role owner or guardian. Each profile includes its registration fields, planning details, interests and preference notes, current version and current-value provenance. Provenance records manual approval or an approved Assistant suggestion, the actor and approval time; another adult's conversation reference is omitted. No previous values are retained. Connected-service imports are not supported.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"children":{"items":{"$ref":"#/components/schemas/FamilyChildProfile"},"type":"array"}},"required":["children"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid profile input"},"401":{"description":"Current account required"},"404":{"description":"Profile not found for this owner"},"409":{"description":"Stale version or profile count limit"}},"security":[{"AccountCredential":[]}],"summary":"List profiles you own or have accepted guardian access to","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/children\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List profiles you own or have accepted guardian access to"}],"x-internal":true},"post":{"description":"Creates one of up to 20 owned profiles from approved values. A planning label or first and last names is required; registration reuse needs both names and defaults to false. Fields are canonical registration strings; preferences hold interests with an unknown/none/listed status and notes; planning holds structured planning details. Each current value records source, actor, approval time and version. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyChildInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"child":{"$ref":"#/components/schemas/FamilyChildProfile"}},"required":["child"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid profile input"},"401":{"description":"Current account required"},"404":{"description":"Profile not found for this owner"},"409":{"description":"Stale version or profile count limit"}},"security":[{"AccountCredential":[]}],"summary":"Create a manually approved child profile","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/children\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Create a manually approved child profile"}],"x-internal":true}},"/api/users/viewer/children/{childId}":{"delete":{"description":"DELETE {version} permanently removes the profile, guardian memberships, invitations, care requirement links and child-linked remembered facts; submitted registration snapshots and receipts remain. Owner only. Stale versions return 409.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"version":{"minimum":1,"type":"integer"}},"required":["version"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"deleted":{"const":true,"type":"boolean"}},"required":["deleted"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid profile input"},"401":{"description":"Current account required"},"404":{"description":"Profile not found for this owner"},"409":{"description":"Stale version or profile count limit"}},"security":[{"AccountCredential":[]}],"summary":"Permanently remove the reusable profile; existing registration snapshots remain","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":1}'","title":"Permanently remove the reusable profile; existing registration snapshots remain"}],"x-internal":true},"patch":{"description":"Applies a narrow correction to fields, preferences.notes, preferences.interests ({status, values}), planning.label, planning.age, planning.gradeSchoolYear or planning.requirements ({status, items}); null removes a value. reuseAllowed cannot be changed here. Owner or current guardian; locks the actor and profile and rechecks membership before saving. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyCorrection"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"child":{"$ref":"#/components/schemas/FamilyChildProfile"}},"required":["child"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Correct named child profile values without replacing the profile","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X PATCH \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":3,\"changes\":{\"child.allergies\":null,\"planning.requirements\":{\"status\":\"none\",\"items\":[]}}}'","title":"Remove an allergy note and record that there are no participation requirements"}],"x-internal":true},"put":{"description":"PUT fully replaces fields and preferences with the current version; omitted or blank optional fields are removed. Omitting planning keeps the saved planning so older clients cannot clear it; sending planning replaces it. Only the owner may change reuseAllowed. Unchanged values retain provenance; changed values record the acting account, source and new version. Stale versions return 409. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/FamilyChildInput"},{"required":["version"],"type":"object"}]}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"child":{"$ref":"#/components/schemas/FamilyChildProfile"}},"required":["child"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid profile input"},"401":{"description":"Current account required"},"404":{"description":"Profile not found for this owner"},"409":{"description":"Stale version or profile count limit"}},"security":[{"AccountCredential":[]}],"summary":"Correct an owned or shared child profile using its current version","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X PUT \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Correct an owned or shared child profile using its current version"}],"x-internal":true}},"/api/users/viewer/children/{childId}/confirmations":{"post":{"description":"Records a fresh approval of the named current values (provenance keys such as guardian.email, preferences.interests or planning.age) without changing them. Owner or current guardian. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyReconfirmation"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"child":{"$ref":"#/components/schemas/FamilyChildProfile"}},"required":["child"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Reconfirm unchanged child profile values","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Child profiles are visible to their owner and accepted active guardians; unrelated accounts receive 404.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID/confirmations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":4,\"keys\":[\"child.grade\",\"planning.gradeSchoolYear\"]}'","title":"Reconfirm the saved grade and its school year"}],"x-internal":true}},"/api/users/viewer/children/{childId}/guardians":{"get":{"description":"Current profile owner only; machine, service and delegated-service credentials are rejected. Cookie mutations require CSRF. GET returns active guardian accounts and unexpired pending invitations. It never returns invitation tokens, token hashes, or acceptance links. A profile has at most five active or pending guardians in addition to its owner.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"guardians":{"items":{"$ref":"#/components/schemas/ChildGuardian"},"type":"array"},"invitations":{"items":{"$ref":"#/components/schemas/ChildInvitation"},"type":"array"}},"required":["guardians","invitations"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid invitation input or missing explicit approval"},"401":{"description":"Current account required"},"403":{"description":"Owner-only action or current verified recipient email required"},"404":{"description":"Profile, guardian or invitation not available to this account"},"409":{"description":"Duplicate pending invitation or guardian limit"},"429":{"description":"Invitation creation rate limit"}},"security":[{"AccountCredential":[]}],"summary":"Review guardian access and pending invitations","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Owner-only guardian management; API_ASSISTANT_ORIGINS are not trusted on these routes.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID/guardians\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Review guardian access and pending invitations"}],"x-internal":true}},"/api/users/viewer/children/{childId}/guardians/{userId}":{"delete":{"description":"Current profile owner only; machine, service and delegated-service credentials are rejected. Cookie mutations require CSRF. DELETE removes this child’s guardian membership. Future profile reads, corrections and registration reuse recheck membership and refuse after revocation. Other children and existing registration receipts are unchanged.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"userId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"revoked":{"const":true,"type":"boolean"}},"required":["revoked"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid invitation input or missing explicit approval"},"401":{"description":"Current account required"},"403":{"description":"Owner-only action or current verified recipient email required"},"404":{"description":"Profile, guardian or invitation not available to this account"},"409":{"description":"Duplicate pending invitation or guardian limit"},"429":{"description":"Invitation creation rate limit"}},"security":[{"AccountCredential":[]}],"summary":"Remove guardian access","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Owner-only guardian management; API_ASSISTANT_ORIGINS are not trusted on these routes.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID/guardians/$USER_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Remove guardian access"}],"x-internal":true}},"/api/users/viewer/children/{childId}/invitations":{"post":{"description":"Current profile owner only; machine, service and delegated-service credentials are rejected. Cookie mutations require CSRF. POST {email} creates an invitation valid for seven days. The response reveals inviteUrl once and reports emailSent. Configured email delivery is attempted after commit; failed or unavailable email delivery leaves a usable copy link. The fragment contains 32 random bytes encoded as 43 URL-safe base64 characters; only its SHA-256 hash is stored. The invitee must verify the matching current account email, review the invitation, and explicitly accept. Creating an invitation grants no access. Duplicate pending addresses or the five-guardian limit return 409; creation is limited to 20 invitations per account per hour.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"email":{"format":"email","maxLength":254,"type":"string"}},"required":["email"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"emailSent":{"type":"boolean"},"invitation":{"$ref":"#/components/schemas/ChildInvitation"},"inviteUrl":{"description":"Revealed once; token lives in the URL fragment.","format":"uri","type":"string"}},"required":["invitation","inviteUrl","emailSent"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid invitation input or missing explicit approval"},"401":{"description":"Current account required"},"403":{"description":"Owner-only action or current verified recipient email required"},"404":{"description":"Profile, guardian or invitation not available to this account"},"409":{"description":"Duplicate pending invitation or guardian limit"},"429":{"description":"Invitation creation rate limit"}},"security":[{"AccountCredential":[]}],"summary":"Invite another guardian to this child profile","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Owner-only guardian management; API_ASSISTANT_ORIGINS are not trusted on these routes.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID/invitations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Invite another guardian to this child profile"}],"x-internal":true}},"/api/users/viewer/children/{childId}/invitations/{invitationId}":{"delete":{"description":"Current profile owner only; machine, service and delegated-service credentials are rejected. Cookie mutations require CSRF. DELETE revokes an unaccepted invitation for this child. Acceptance and revocation serialize on the profile, so a revoked invitation cannot later grant access. Use the guardian removal route after an invitation has been accepted.","parameters":[{"in":"path","name":"childId","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"invitationId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"revoked":{"const":true,"type":"boolean"}},"required":["revoked"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid invitation input or missing explicit approval"},"401":{"description":"Current account required"},"403":{"description":"Owner-only action or current verified recipient email required"},"404":{"description":"Profile, guardian or invitation not available to this account"},"409":{"description":"Duplicate pending invitation or guardian limit"},"429":{"description":"Invitation creation rate limit"}},"security":[{"AccountCredential":[]}],"summary":"Revoke an invitation","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Owner-only guardian management; API_ASSISTANT_ORIGINS are not trusted on these routes.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/users/viewer/children/$CHILD_ID/invitations/$INVITATION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Revoke an invitation"}],"x-internal":true}},"/api/users/viewer/family-context":{"get":{"description":"Returns version family-context-v1: permitted children (label, computed age or bounded reported age, grade with school-year currency, interests, required and preferred participation conditions, preference notes), the adult's own household preferences, active and upcoming care requirements with their effective time zone and inherited budget/travel, hard conflicts that need clarification, up to 25 saved tracking options (not enrollment or availability), up to 20 of the adult's own School's Out registrations for permitted children (complete:false; not a calendar), unexpired approved facts, and per-value source, approval time and version. Omits last names, birthdates, allergies, registration notes (child.notes), guardian and emergency contacts, reuse permission, invitations and account IDs. Approved preference notes remain in the projection. Generic table, canonical SQL and research Ask never read these records. Booked-session context includes the ordered `prices` collection, scheduleConfigurations, and independently recorded care quotes. Effective date bounds and uniform clocks summarize explicit configurations; sparse dates never imply daily attendance.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"familyContext":{"type":"object"}},"required":["familyContext"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"401":{"description":"Current account required"}},"security":[{"AccountCredential":[]}],"summary":"Read the bounded family context the parent Assistant may use","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/family-context\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read the Assistant family context"}],"x-internal":true}},"/api/users/viewer/family-memory":{"get":{"description":"Returns the adult's explicitly approved facts. Child-linked facts appear only while the adult can access that child.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"facts":{"items":{"$ref":"#/components/schemas/FamilyMemoryFact"},"type":"array"}},"required":["facts"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"401":{"description":"Current account required"}},"security":[{"AccountCredential":[]}],"summary":"List approved remembered facts","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/family-memory\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List remembered facts"}],"x-internal":true},"post":{"description":"Requires approve:true and the exact statement (at most 500 characters), a category, an optional permitted child and an optional future expiry, up to 100 per account. A conversation mentioning something never saves it. Use structured profile, household and care fields instead of facts for values they cover. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"approve":{"const":true},"category":{"enum":["activity_history","logistics","preference","other"]},"childId":{"format":"uuid","type":"string"},"expiresOn":{"format":"date","type":"string"},"source":{"$ref":"#/components/schemas/FamilyApprovalSource"},"statement":{"maxLength":500,"minLength":1,"type":"string"}},"required":["approve","statement","category"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"fact":{"$ref":"#/components/schemas/FamilyMemoryFact"}},"required":["fact"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Remember an explicitly approved statement","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/family-memory\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"approve\":true,\"statement\":\"Loved the pottery camp last summer\",\"category\":\"activity_history\",\"childId\":\"$CHILD_ID\"}'","title":"Remember an approved activity history fact"}],"x-internal":true}},"/api/users/viewer/family-memory/{factId}":{"delete":{"description":"DELETE {version} permanently removes the fact. Stale versions return 409.","parameters":[{"in":"path","name":"factId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"version":{"minimum":1,"type":"integer"}},"required":["version"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"deleted":{"const":true}},"required":["deleted"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Forget a remembered fact","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/users/viewer/family-memory/$FACT_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":2}'","title":"Forget a remembered fact"}],"x-internal":true},"patch":{"description":"Replaces statement, category, childId or expiresOn; null removes childId or expiresOn. The new approval replaces the previous source reference. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","parameters":[{"in":"path","name":"factId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyCorrection"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"fact":{"$ref":"#/components/schemas/FamilyMemoryFact"}},"required":["fact"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Correct a remembered fact","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X PATCH \"https://apis.schoolsoutapp.com/api/users/viewer/family-memory/$FACT_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":1,\"changes\":{\"statement\":\"Loved the pottery camp in 2026\"}}'","title":"Correct a remembered statement"}],"x-internal":true}},"/api/users/viewer/family-memory/{factId}/confirmations":{"post":{"description":"Renews approval of the current statement; an expired fact must be corrected with a new expiry instead. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","parameters":[{"in":"path","name":"factId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"source":{"$ref":"#/components/schemas/FamilyApprovalSource"},"version":{"minimum":1,"type":"integer"}},"required":["version"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"fact":{"$ref":"#/components/schemas/FamilyMemoryFact"}},"required":["fact"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Reconfirm an unchanged remembered fact","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/family-memory/$FACT_ID/confirmations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":2}'","title":"Reconfirm a remembered fact"}],"x-internal":true}},"/api/users/viewer/gmail":{"delete":{"description":"GET returns { connected, emailAddress, scope, connected_at } for the viewer's own Gmail grant, with nulls when no inbox is connected; the token is never returned. DELETE revokes the refresh token at Google, then deletes the grant and returns { connected: false, revoked }. A token Google already considers invalid counts as revoked. Any other Google failure returns 502 and keeps the grant so the request can be retried; a grant reconnected during the request returns 409.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"connected":{"const":false},"revoked":{"description":"Whether Google confirmed the grant revoked or already invalid.","type":"boolean"}},"required":["connected","revoked"],"type":"object"}}},"description":"Success. Values are top-level; no provider token is returned."},"400":{"description":"Invalid, expired or reused flow, missing proof, or rejected Google grant."},"401":{"description":"Current adult account required; service delegation and machine keys are refused."},"409":{"description":"A grant was reconnected during revocation; retry against current state."},"501":{"description":"Gmail OAuth and token-sealing settings are not configured."},"502":{"description":"Google revocation failed; the stored connection is retained."}},"security":[{"AccountCredential":[]}],"summary":"Revoke and remove the Gmail grant","tags":["Internal Gmail"],"x-auth":"Signed-in adult only; account cookie or account credential, never delegated service or machine keys. Cookie requests require CSRF from a trusted or API_ASSISTANT_ORIGINS origin.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/users/viewer/gmail\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Disconnect Gmail"}],"x-internal":true},"get":{"description":"GET returns { connected, emailAddress, scope, connected_at } for the viewer's own Gmail grant, with nulls when no inbox is connected; the token is never returned. DELETE revokes the refresh token at Google, then deletes the grant and returns { connected: false, revoked }. A token Google already considers invalid counts as revoked. Any other Google failure returns 502 and keeps the grant so the request can be retried; a grant reconnected during the request returns 409.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"connected":{"type":"boolean"},"connected_at":{"description":"Original connection time, or null when disconnected.","format":"date-time","type":["string","null"]},"emailAddress":{"description":"The authorized Gmail address, or null when disconnected.","type":["string","null"]},"scope":{"description":"Granted Google scopes, or null when disconnected.","type":["string","null"]}},"required":["connected","emailAddress","scope","connected_at"],"type":"object"}}},"description":"Success. Values are top-level; no provider token is returned."},"401":{"description":"Current adult account required; service delegation and machine keys are refused."}},"security":[{"AccountCredential":[]}],"summary":"Read the connected Gmail address","tags":["Internal Gmail"],"x-auth":"Signed-in adult only; account cookie or account credential, never delegated service or machine keys. Cookie requests require CSRF from a trusted or API_ASSISTANT_ORIGINS origin.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/gmail\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read the Gmail connection"}],"x-internal":true}},"/api/users/viewer/gmail/authorization":{"post":{"description":"Starts Gmail access and returns {url}. Web requests use an optional parent-site redirect and receive the browser nonce cookie. Native requests send {redirect, challenge}, an exact schoolsout://gmail-callback (or exp://host:port/--/gmail-callback outside production) and unpadded base64url SHA-256 app proof. Their URL is a one-use 10-minute API browser bootstrap that sets its own cookie before Google consent. No account key or verifier belongs in that URL.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"challenge":{"description":"Unpadded base64url SHA-256 of the app-held verifier. Required for native callbacks and forbidden for web callbacks.","pattern":"^[A-Za-z0-9_-]{43}$","type":"string"},"redirect":{"description":"Allowed parent page for web, fixed schoolsout://gmail-callback for installed apps, or the narrow Expo Go callback in development.","maxLength":2048,"type":"string"}},"required":[],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"url":{"description":"Google consent URL for web; one-use API browser bootstrap URL for native.","format":"uri","type":"string"}},"required":["url"],"type":"object"}}},"description":"Success. Values are top-level; no provider token is returned."},"400":{"description":"Invalid, expired or reused flow, missing proof, or rejected Google grant."},"401":{"description":"Current adult account required; service delegation and machine keys are refused."},"501":{"description":"Gmail OAuth and token-sealing settings are not configured."}},"security":[{"AccountCredential":[]}],"summary":"Start a browser or app Gmail connection","tags":["Internal Gmail"],"x-auth":"Signed-in adult only; account cookie or account credential, never delegated service or machine keys. Cookie requests require CSRF from a trusted or API_ASSISTANT_ORIGINS origin.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/gmail/authorization\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"redirect\":\"schoolsout://gmail-callback\",\"challenge\":\"$CHALLENGE\"}'","title":"Start a Gmail connection from the installed app"}],"x-internal":true}},"/api/users/viewer/gmail/complete":{"post":{"description":"Native completion accepts {code, verifier}. Consumes the five-minute ticket only for its starting adult; the original S256 proof must match a 43–128 character verifier. Exchanges the sealed Google authorization code and saves the grant only after validation, then returns top-level {connected, emailAddress, scope, connected_at}. Missing/wrong proof, expiry and replay return 400; a different adult cannot consume the ticket. No token is returned.","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"code":{"description":"One-time completion ticket returned to the app, not the Google code.","format":"uuid","type":"string"},"verifier":{"description":"Original app-held proof verifier, sent only in this authenticated body.","maxLength":128,"minLength":43,"type":"string"}},"required":["code","verifier"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"connected":{"type":"boolean"},"connected_at":{"description":"Original connection time, or null when disconnected.","format":"date-time","type":["string","null"]},"emailAddress":{"description":"The authorized Gmail address, or null when disconnected.","type":["string","null"]},"scope":{"description":"Granted Google scopes, or null when disconnected.","type":["string","null"]}},"required":["connected","emailAddress","scope","connected_at"],"type":"object"}}},"description":"Success. Values are top-level; no provider token is returned."},"400":{"description":"Invalid, expired or reused flow, missing proof, or rejected Google grant."},"401":{"description":"Current adult account required; service delegation and machine keys are refused."},"501":{"description":"Gmail OAuth and token-sealing settings are not configured."}},"security":[{"AccountCredential":[]}],"summary":"Complete a native Gmail connection with app proof","tags":["Internal Gmail"],"x-auth":"Signed-in adult only; account cookie or account credential, never delegated service or machine keys. Cookie requests require CSRF from a trusted or API_ASSISTANT_ORIGINS origin.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/gmail/complete\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"code\":\"$COMPLETION_TICKET\",\"verifier\":\"$VERIFIER\"}'","title":"Complete a native Gmail connection"}],"x-internal":true}},"/api/users/viewer/household":{"delete":{"description":"DELETE {version} erases household preferences and provenance and advances the retained revision. Stale versions return 409. GET returns empty preferences with the new revision; resaving requires that current revision.","requestBody":{"content":{"application/json":{"schema":{"properties":{"version":{"minimum":1,"type":"integer"}},"required":["version"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"deleted":{"const":true}},"required":["deleted"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Remove all household preferences","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X DELETE \"https://apis.schoolsoutapp.com/api/users/viewer/household\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":2}'","title":"Remove household preferences"}],"x-internal":true},"get":{"description":"Returns the signed-in adult’s private household preferences, provenance, and version. Version 0 means never saved. After deletion, preferences and provenance are empty but the incremented version remains; use this version to save again.","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"household":{"$ref":"#/components/schemas/FamilyHousehold"}},"required":["household"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"401":{"description":"Current account required"}},"security":[{"AccountCredential":[]}],"summary":"Read the signed-in adult's household preferences","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/household\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"Read household preferences"}],"x-internal":true},"patch":{"description":"Version 0 saves the first preferences; later changes need the current version. Each named key (searchArea, timezone, budget, travel, caregiverAvailability) is replaced; null removes it. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval. After deletion, read and submit the retained current version; version 0 is only valid before the first save.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyCorrection"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"household":{"$ref":"#/components/schemas/FamilyHousehold"}},"required":["household"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Save or correct named household preferences","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X PATCH \"https://apis.schoolsoutapp.com/api/users/viewer/household\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":0,\"changes\":{\"budget\":{\"amount\":450,\"currency\":\"USD\",\"period\":\"week\",\"scope\":\"per_child\",\"limit\":\"hard_cap\"}}}'","title":"Save a weekly per-child hard budget cap"}],"x-internal":true}},"/api/users/viewer/household/confirmations":{"post":{"description":"Records a fresh approval of the named saved preferences without changing them. The authenticated viewer is always the approving actor. Optional source {type:\"manual\"} or {type:\"assistant\", conversationId, turnId} names one of the viewer's own completed Assistant turns that proposed the change; the write itself is the explicit approval.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FamilyReconfirmation"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"household":{"$ref":"#/components/schemas/FamilyHousehold"}},"required":["household"],"type":"object"},"success":{"const":true,"type":"boolean"}},"required":["success","data"],"type":"object"}}},"description":"Success"},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Stale version, limit, or nothing to reconfirm"}},"security":[{"AccountCredential":[]}],"summary":"Reconfirm unchanged household preferences","tags":["Internal family planning"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/household/confirmations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"version\":2,\"keys\":[\"timezone\"]}'","title":"Reconfirm the household time zone"}],"x-internal":true}},"/api/users/viewer/registrations":{"get":{"description":"Requires an account session or account credential belonging to the parent. Machine keys, service and delegated-service credentials are rejected. Cookie mutations require the current CSRF token. Responses are private and not cached.","responses":{"200":{"description":"Latest 200 owner-scoped registrations, newest first; data.registrations carries id, organizationId, organizationName, childProfileId (nullable after removal), profileVersion, confirmationCode, status, createdAt and authorization. Authorization carries version, purpose, approvedAt, sharedFields, reusedFields, fieldLabels and consentStatements. Previously submitted registrations remain after profile removal."},"401":{"description":"Sign-in required"},"403":{"description":"Account credential required"}},"security":[{"AccountCredential":[]}],"summary":"List your registration disclosure receipts","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Registration receipts belong to the submitting adult.","x-curl-examples":[{"code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/registrations\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\"","title":"List your registration disclosure receipts"}],"x-internal":true}},"/api/users/viewer/registrations/{id}":{"post":{"description":"Current account owns the child profile or has accepted active guardian access; cookie mutations require CSRF. Machine keys and service impersonation are rejected. Registers with camp id using an explicitly approved saved profile. Send the normal registration body plus profile {id,version}, approveSharing:true and consentStatements [{key,label,text}] matching each accepted form acknowledgement. The transaction locks the submitting account and profile, then rechecks live owner or guardian access, version and owner-controlled reuse permission before allocating capacity. The receipt belongs to the submitting account; joining a profile does not grant access to another account’s registration history. Corrections never rewrite submitted registrations. Stale profile/consent returns 409; inaccessible profiles return 404. Guest registration remains at POST /api/organizations/{id}/registrations.","parameters":[{"description":"Destination organization ID","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"description":"Canonical and custom answers follow the destination’s public registration form. Only visible requested fields are accepted. Consent statements must exactly match accepted acknowledgements in form order. The API checks the current profile version/reuse permission in the same transaction as registration and capacity.","properties":{"acknowledgements":{"type":"object"},"answers":{"type":"object"},"approveSharing":{"const":true,"type":"boolean"},"child":{"type":"object"},"consent":{"const":true,"type":"boolean"},"consentStatements":{"items":{"properties":{"key":{"type":"string"},"label":{"type":"string"},"text":{"type":"string"}},"required":["key","label","text"],"type":"object"},"type":"array"},"emergencyContact":{"type":"object"},"guardian":{"type":"object"},"profile":{"properties":{"id":{"format":"uuid","type":"string"},"version":{"maximum":9007199254740991,"minimum":1,"type":"integer"}},"required":["id","version"],"type":"object"},"secondaryGuardian":{"type":"object"},"sessionIds":{"items":{"format":"uuid","type":"string"},"maxItems":6,"type":"array"},"source":{"type":"object"}},"required":["profile","approveSharing","consentStatements","child","guardian","consent"],"type":"object"}}},"required":true},"responses":{"201":{"description":"Registration receipt in data.registration; approved disclosure persisted atomically"},"400":{"description":"Invalid reference or missing approval"},"401":{"description":"Sign-in required"},"403":{"description":"Account credential required"},"404":{"description":"Camp or owned child profile not found"},"409":{"description":"Profile changed, reuse revoked, form closed, or consent wording changed; reload and review"},"422":{"description":"Registration answers or selected sessions are invalid"}},"security":[{"AccountCredential":[]}],"summary":"Submit an explicitly approved registration using your child profile","tags":["Internal family profiles"],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Registration receipts belong to the submitting adult.","x-curl-examples":[{"code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/registrations/$ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'","title":"Submit an explicitly approved registration using your child profile"}],"x-internal":true}},"/api/users/viewer/payment-method":{"get":{"tags":["Internal family bookings"],"x-internal":true,"summary":"Get the saved card","description":"Returns the saved card, or `null` if the parent hasn’t saved one. After setup, it returns the newest card.","responses":{"200":{"description":"The saved card, or `null`.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["paymentMethod"],"properties":{"paymentMethod":{"oneOf":[{"$ref":"#/components/schemas/BookingPaymentMethod"},{"type":"null"}]}}}}},"example":{"success":true,"data":{"paymentMethod":{"brand":"visa","last4":"4242"}}}}}},"401":{"description":"Current account required. A request without a session or credential answers {\"authorized\": false}; a machine key or delegated service request answers the error envelope with message \"unauthorized.\", because these routes act only as the signed-in parent."},"404":{"$ref":"#/components/responses/BookingsDisabled"}},"security":[{"AccountCredential":[]}],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. The route is registered only when the API runs with BOOKINGS_ENABLED=true; otherwise it returns 404.","x-curl-examples":[{"title":"Get the saved card","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/payment-method\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/users/viewer/payment-method/setup":{"post":{"tags":["Internal family bookings"],"x-internal":true,"summary":"Start card setup","description":"Returns a Stripe Checkout URL in setup mode. Send the browser there; Stripe returns the parent to `returnUrl` afterward.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["returnUrl"],"properties":{"returnUrl":{"type":"string","format":"uri","description":"Absolute URL whose origin is in the API’s `REDIRECT_ALLOWLIST`."}}},"example":{"returnUrl":"https://data.schoolsoutapp.com/family/bookings/new?session=c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48"}}}},"responses":{"200":{"description":"The Stripe-hosted setup URL.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"}}}}},"example":{"success":true,"data":{"url":"https://checkout.stripe.com/c/pay/cs_live_..."}}}}},"400":{"description":"The body isn’t exactly `{ returnUrl }`, or its origin isn’t allowed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"returnUrl must be an allowed absolute URL.","data":null}}}},"401":{"description":"Current account required. A request without a session or credential answers {\"authorized\": false}; a machine key or delegated service request answers the error envelope with message \"unauthorized.\", because these routes act only as the signed-in parent."},"404":{"$ref":"#/components/responses/BookingsDisabled"},"503":{"description":"Stripe couldn’t start setup. Nothing was saved; try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"Card setup is unavailable. Try again shortly.","data":null}}}}},"security":[{"AccountCredential":[]}],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. The route is registered only when the API runs with BOOKINGS_ENABLED=true; otherwise it returns 404.","x-curl-examples":[{"title":"Start card setup","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/payment-method/setup\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"returnUrl\": \"https://data.schoolsoutapp.com/family/bookings/new?session=c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48\"}'"}]}},"/api/users/viewer/bookings":{"get":{"tags":["Internal family bookings"],"x-internal":true,"summary":"List bookings","description":"Returns the parent’s 100 most recent bookings, newest first. Event history is omitted; get a single booking to read it.","responses":{"200":{"description":"The parent’s bookings.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["bookings"],"properties":{"bookings":{"type":"array","items":{"$ref":"#/components/schemas/FamilyBooking"}}}}}},"example":{"success":true,"data":{"bookings":[{"id":"6f1d2c3b-4a5e-4f60-8b7a-1c2d3e4f5a6b","phase":"booked","status":"confirmed","paymentStatus":"captured","childProfileId":"1f8a3c5e-7b2d-4e9f-a6c1-4d0b8e2f7a93","organization":{"id":"9e4f7a21-3b6c-4d8e-a1f5-2c7b0d9e6f34","name":"Lakeside Science Camp"},"session":{"id":"c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48","name":"Robotics Week","startDate":"2027-07-12","endDate":"2027-07-16"},"approval":{"approvedAt":"2026-10-09T17:00:00Z","maxSpend":{"amountCents":45000,"currency":"USD"},"allowWaitlist":true,"autoAcceptDecisions":false,"sharedFields":["child.birthDate"]},"progressStage":null,"hold":null,"decision":null,"decisions":[],"receipt":{"providerReference":"LSC-20931","providerStatus":"enrolled","amount":{"amountCents":42500,"currency":"USD"},"confirmedAt":"2026-10-09T17:06:35Z"},"failure":null,"checkingWith":null,"pollAfterMs":null,"createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:06:41Z"}]}}}}},"401":{"description":"Current account required. A request without a session or credential answers {\"authorized\": false}; a machine key or delegated service request answers the error envelope with message \"unauthorized.\", because these routes act only as the signed-in parent."},"404":{"$ref":"#/components/responses/BookingsDisabled"}},"security":[{"AccountCredential":[]}],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. The route is registered only when the API runs with BOOKINGS_ENABLED=true; otherwise it returns 404.","x-curl-examples":[{"title":"List bookings","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/bookings\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]},"post":{"tags":["Internal family bookings"],"x-internal":true,"summary":"Approve a booking","description":"Records the parent’s approval, places a hold on their card for the spending limit, and sends the booking to Hallpass. A fast checkout can finish within this request; otherwise, follow the booking until it settles. The child profile must allow reuse, as it does for registration.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingApprovalInput"}}}},"responses":{"201":{"description":"The new booking. Its status may already be past `authorizing`.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["booking"],"properties":{"booking":{"$ref":"#/components/schemas/FamilyBookingDetail"}}}}},"example":{"success":true,"data":{"booking":{"id":"6f1d2c3b-4a5e-4f60-8b7a-1c2d3e4f5a6b","phase":"in_progress","status":"accepted","paymentStatus":"held","childProfileId":"1f8a3c5e-7b2d-4e9f-a6c1-4d0b8e2f7a93","organization":{"id":"9e4f7a21-3b6c-4d8e-a1f5-2c7b0d9e6f34","name":"Lakeside Science Camp"},"session":{"id":"c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48","name":"Robotics Week","startDate":"2027-07-12","endDate":"2027-07-16"},"approval":{"approvedAt":"2026-10-09T17:00:00Z","maxSpend":{"amountCents":45000,"currency":"USD"},"allowWaitlist":true,"autoAcceptDecisions":false,"sharedFields":["child.birthDate"]},"progressStage":null,"hold":null,"decision":null,"decisions":[],"receipt":null,"failure":null,"checkingWith":null,"pollAfterMs":2000,"createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:06:41Z","events":[{"kind":"approval_granted","status":"authorizing","actor":"parent","summary":"Approved the booking with a spending limit of 450.00 USD.","createdAt":"2026-10-09T17:00:00Z"},{"kind":"payment_hold_placed","status":"prepared","actor":"system","summary":"Held 450.00 USD on the family card.","createdAt":"2026-10-09T17:00:01Z"},{"kind":"task_submitted","status":"submitting","actor":"system","summary":"Sent the approved booking to Hallpass.","createdAt":"2026-10-09T17:00:01Z"}]}}}}}},"200":{"description":"The existing booking for this `idempotencyKey`, returned because the request was a replay.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["booking"],"properties":{"booking":{"$ref":"#/components/schemas/FamilyBookingDetail"}}}}}}}},"400":{"description":"The approval is invalid: an unknown property, `approveBooking` not `true`, a spending limit or currency that isn’t allowed, a field that can’t be shared or is missing from the profile, or too many answers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"Approve the booking to continue.","data":null}}}},"401":{"description":"Current account required. A request without a session or credential answers {\"authorized\": false}; a machine key or delegated service request answers the error envelope with message \"unauthorized.\", because these routes act only as the signed-in parent."},"404":{"description":"Bookings are off, the child profile isn’t available to this parent, or the session is no longer listed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"That session is no longer available.","data":null}}}},"409":{"description":"The profile changed or no longer allows reuse, the `idempotencyKey` was reused with different details, or the child already has an active or confirmed booking for this session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"This child already has a booking in progress or confirmed for this session.","data":null}}}}},"security":[{"AccountCredential":[]}],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. The route is registered only when the API runs with BOOKINGS_ENABLED=true; otherwise it returns 404.","x-curl-examples":[{"title":"Approve a booking","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/bookings\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"idempotencyKey\": \"0b7c3f52-9a41-4e2d-8f6a-3c1d5e7b9a20\", \"childProfileId\": \"1f8a3c5e-7b2d-4e9f-a6c1-4d0b8e2f7a93\", \"childProfileVersion\": 4, \"sessionId\": \"c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48\", \"maxSpend\": {\"amountCents\": 45000, \"currency\": \"USD\"}, \"allowWaitlist\": true, \"autoAcceptDecisions\": false, \"shareFields\": [\"child.birthDate\"], \"answers\": [{\"key\": \"photo_consent\", \"label\": \"Photo consent\", \"value\": false}], \"approveBooking\": true}'"}]}},"/api/users/viewer/bookings/{bookingId}":{"get":{"tags":["Internal family bookings"],"x-internal":true,"summary":"Get a booking","description":"Returns one booking with its full event history. Read it again after `pollAfterMs`. A booking that belongs to another account looks exactly like one that doesn’t exist.","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The booking and its events.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["booking"],"properties":{"booking":{"$ref":"#/components/schemas/FamilyBookingDetail"}}}}},"example":{"success":true,"data":{"booking":{"id":"6f1d2c3b-4a5e-4f60-8b7a-1c2d3e4f5a6b","phase":"booked","status":"confirmed","paymentStatus":"captured","childProfileId":"1f8a3c5e-7b2d-4e9f-a6c1-4d0b8e2f7a93","organization":{"id":"9e4f7a21-3b6c-4d8e-a1f5-2c7b0d9e6f34","name":"Lakeside Science Camp"},"session":{"id":"c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48","name":"Robotics Week","startDate":"2027-07-12","endDate":"2027-07-16"},"approval":{"approvedAt":"2026-10-09T17:00:00Z","maxSpend":{"amountCents":45000,"currency":"USD"},"allowWaitlist":true,"autoAcceptDecisions":false,"sharedFields":["child.birthDate"]},"progressStage":null,"hold":null,"decision":null,"decisions":[],"receipt":{"providerReference":"LSC-20931","providerStatus":"enrolled","amount":{"amountCents":42500,"currency":"USD"},"confirmedAt":"2026-10-09T17:06:35Z"},"failure":null,"checkingWith":null,"pollAfterMs":null,"createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:06:41Z","events":[{"kind":"approval_granted","status":"authorizing","actor":"parent","summary":"Approved the booking with a spending limit of 450.00 USD.","createdAt":"2026-10-09T17:00:00Z"},{"kind":"payment_hold_placed","status":"prepared","actor":"system","summary":"Held 450.00 USD on the family card.","createdAt":"2026-10-09T17:00:01Z"},{"kind":"task_submitted","status":"submitting","actor":"system","summary":"Sent the approved booking to Hallpass.","createdAt":"2026-10-09T17:00:01Z"},{"kind":"confirmation_received","status":"confirmed","actor":"hallpass","summary":"The camp confirmed reference LSC-20931.","createdAt":"2026-10-09T17:06:40Z"},{"kind":"payment_captured","status":"confirmed","actor":"system","summary":"Charged 425.00 USD to the family card.","createdAt":"2026-10-09T17:06:41Z"}]}}}}}},"401":{"description":"Current account required. A request without a session or credential answers {\"authorized\": false}; a machine key or delegated service request answers the error envelope with message \"unauthorized.\", because these routes act only as the signed-in parent."},"404":{"description":"No such booking for this parent, or bookings are off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"Booking not found.","data":null}}}}},"security":[{"AccountCredential":[]}],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. The route is registered only when the API runs with BOOKINGS_ENABLED=true; otherwise it returns 404.","x-curl-examples":[{"title":"Get a booking","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/bookings/$BOOKING_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/users/viewer/bookings/{bookingId}/decisions/{decisionId}":{"post":{"tags":["Internal family bookings"],"x-internal":true,"summary":"Answer a camp question","description":"Accepts one of the offered options, or declines. Declining ends the booking and releases the hold.","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"decisionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["outcome"],"properties":{"outcome":{"type":"string","enum":["accept","decline"]},"optionId":{"type":"string","description":"Required to accept; must be absent to decline."},"answer":{"type":["string","null"],"minLength":1,"maxLength":2000,"description":"Your typed answer. Required to accept an `answer_required` decision; omit it otherwise."}}},"examples":{"accept":{"value":{"outcome":"accept","optionId":"medium"}},"decline":{"value":{"outcome":"decline"}}}}}},"responses":{"200":{"description":"The answer was recorded and checkout resumes.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["booking"],"properties":{"booking":{"$ref":"#/components/schemas/FamilyBookingDetail"}}}}}}}},"400":{"description":"`optionId` is missing when accepting, present when declining, or not one of the offered options.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"Choose one of the offered options.","data":null}}}},"401":{"description":"Current account required. A request without a session or credential answers {\"authorized\": false}; a machine key or delegated service request answers the error envelope with message \"unauthorized.\", because these routes act only as the signed-in parent."},"404":{"$ref":"#/components/responses/BookingNotFound"},"409":{"description":"The question was already answered or has expired, or the booking is briefly busy. Read the booking again instead of retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"That decision is no longer waiting for an answer.","data":null}}}},"503":{"description":"Hallpass couldn’t be reached. Nothing was recorded; try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"The answer could not be sent. Try again.","data":null}}}}},"security":[{"AccountCredential":[]}],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. The route is registered only when the API runs with BOOKINGS_ENABLED=true; otherwise it returns 404.","x-curl-examples":[{"title":"Answer a camp question","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/bookings/$BOOKING_ID/decisions/$DECISION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"outcome\": \"accept\", \"optionId\": \"medium\"}'"}]}},"/api/users/viewer/bookings/{bookingId}/cancel":{"post":{"tags":["Internal family bookings"],"x-internal":true,"summary":"Cancel a booking","description":"Cancels the booking and releases the hold, as long as the camp’s checkout hasn’t started payment.","parameters":[{"name":"bookingId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The cancellation was recorded. The status becomes `cancelled` once Hallpass confirms.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["booking"],"properties":{"booking":{"$ref":"#/components/schemas/FamilyBookingDetail"}}}}}}}},"401":{"description":"Current account required. A request without a session or credential answers {\"authorized\": false}; a machine key or delegated service request answers the error envelope with message \"unauthorized.\", because these routes act only as the signed-in parent."},"404":{"$ref":"#/components/responses/BookingNotFound"},"409":{"description":"The booking is already final, checkout has started payment, or the booking is briefly busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingError"},"example":{"error":true,"message":"Checkout has started with the camp and can no longer be cancelled here.","data":null}}}}},"security":[{"AccountCredential":[]}],"x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. The route is registered only when the API runs with BOOKINGS_ENABLED=true; otherwise it returns 404.","x-curl-examples":[{"title":"Cancel a booking","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/bookings/$BOOKING_ID/cancel\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/activities/scores":{"get":{"description":"Returns score summaries for up to 24 distinct canonical activities from ?ids=UUID,UUID with scores, missing, scoringVersion, and tier. The default and cached=false calculate live scores. Optional cached=true returns persisted summaries without evidence reads or calculation; scores and missing follow request order, and missing caches never trigger live fallback. Cached reads exclude deleted and blacklisted records even for moderation readers and deny all previews. Both modes retain Starter+ access. cached accepts one exact true or false value; malformed or repeated values return 400.","parameters":[{"description":"Comma-separated distinct record UUIDs, up to 24. UUID case is ignored.","in":"query","name":"ids","required":true,"schema":{"type":"string"}},{"description":"One exact true or false value. true reads persisted summaries; omitted or false calculates live summaries.","in":"query","name":"cached","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"missing":{"items":{"format":"uuid","type":"string"},"type":"array"},"scores":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"scoringVersion":{"type":"string"},"tier":{"type":"string"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Score summaries and IDs with no available result. Cached mode never recalculates missing scores."},"400":{"description":"Missing, invalid, or excessive IDs, or malformed/repeated cached values."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"403":{"description":"Cached score summaries are unavailable in preview."},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Read activity score summaries","tags":["Organization catalog"],"x-auth":"Starter+ account cookie, account header, or permitted machine key. Cached reads deny all previews.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/activities/scores\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"ids=$ACTIVITY_ID\" \\\n  --data-urlencode \"cached=true\"","title":"Read activity cached summaries"}]}},"/api/activities/{id}/provenance":{"get":{"description":"Returns data.activity with id and visible bookkeeping moved from normal reads. Only authorized ADMIN readers additionally receive field_provenance, source_records, merge_jobs, and relationship_jobs. Moved fields are configuration_id, external_ids, created_at, updated_at, source_created_at, field_provenance, source_records, merge_jobs, and relationship_jobs. Field provenance separates current value ownership (state, sources, value_state) from source checks and field decisions. Entries cover visible fields before sparse projection, including cleared and unknown values. A found or checked_not_found observation can exist without a value change; absence of observation means no recorded check. Sources, latest_observation, and history share a flat record shape; history is newest first. The latest observation follows observed time, while decision history follows contribution time. Omitted field_provenance means unavailable; an absent entry in an available map is unknown. Field citations are distinct from site-scoped scrape URLs.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"activity":{"$ref":"#/components/schemas/CanonicalProvenanceRow"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Canonical activity bookkeeping and authorized history"},"403":{"description":"Provenance is unavailable in preview"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Read activity bookkeeping and provenance","tags":["Organization catalog"],"x-auth":"Account cookie or header, or permitted machine key, from Starter up. Bookkeeping follows the existing field masks. Field provenance and raw histories require an ADMIN user-backed viewer, including an ADMIN-owned machine key; staff, bare service credentials, and membership upgrades do not grant this authority. All previews are denied.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/activities/$ACTIVITY_ID/provenance\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read permitted activity bookkeeping and provenance"}]}},"/api/activities/{id}/score":{"get":{"description":"Returns one canonical activity with its School’s Out activity score as pure JSON: the assembled ActivityScoreInput (the program's fields, sources, continuity signals, and its camp's score and safety cap), the full score with criteria, indicators, sources, caps, flags, and field ledger, and the scoring version. The live activity rubric uses the selected active cover and has no enrollment-pricing criterion. This endpoint calculates the live score and returns its input/evidence separately from normal catalog reads. The embedded canonical record follows the sparse public projection.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"additionalProperties":true,"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Live score, scoring input, canonical record, scoringVersion, tier, and lockedColumns. Organization responses also include moderation and optional peers."},"400":{"description":"Invalid record UUID."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Read one live activity score","tags":["Organization catalog"],"x-auth":"Existing Starter+ score access and field masks apply. Active organization membership retains its scoped detail access.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/activities/$ACTIVITY_ID/score\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read activity live score detail"}]}},"/api/organizations/scores":{"get":{"description":"Returns score summaries for up to 24 distinct canonical organizations from ?ids=UUID,UUID with scores, missing, scoringVersion, and tier. The default and cached=false calculate live scores. Optional cached=true returns persisted summaries without evidence reads or calculation; scores and missing follow request order, and missing caches never trigger live fallback. Organization caches from an older scoring version remain missing until the updated worker refreshes them. Cached reads exclude deleted and blacklisted records even for moderation readers and deny all previews. Both modes retain Starter+ access. cached accepts one exact true or false value; malformed or repeated values return 400.","parameters":[{"description":"Comma-separated distinct record UUIDs, up to 24. UUID case is ignored.","in":"query","name":"ids","required":true,"schema":{"type":"string"}},{"description":"One exact true or false value. true reads persisted summaries; omitted or false calculates live summaries.","in":"query","name":"cached","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"missing":{"items":{"format":"uuid","type":"string"},"type":"array"},"scores":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"scoringVersion":{"type":"string"},"tier":{"type":"string"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Score summaries and IDs with no available result. Cached mode never recalculates missing scores."},"400":{"description":"Missing, invalid, or excessive IDs, or malformed/repeated cached values."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"403":{"description":"Cached score summaries are unavailable in preview."},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Read organization score summaries","tags":["Organization catalog"],"x-auth":"Starter+ account cookie, account header, or permitted machine key. Cached reads deny all previews.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations/scores\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"ids=$ORGANIZATION_ID\" \\\n  --data-urlencode \"cached=true\"","title":"Read organization cached summaries"}]}},"/api/organizations/{id}/provenance/timeline":{"get":{"description":"Returns settled canonical contributions to a camp and its currently associated activities and sessions, including sessions associated through an activity. Entries use accepted merge masks or retained set/clear decisions, never scraper completion, pending or failed jobs, or observation-only checks; same-value confirmations may appear. The page and ADMIN-only value reconstruction share one repeatable-read, read-only snapshot. For each entity on the page, ADMIN before/after values are reconstructed from its current logical projection and full retained per-entity applied history, including contributions outside the requested page, using pipeline contribution precedence and reversal semantics, including URL additions and removals. Each recovered before value becomes the next older contribution's after value; reversed contributions remain marked reversed. Staff receive the same source/entity/time/field summary but restricted value sides and incur no reconstruction. Storage-only bookkeeping fields remain restricted even for ADMIN. This is reconstructed retained history, not immutable snapshots, current field ownership, or a complete audit. The oldest before value, ambiguous legacy URL invalidations, and genuine history gaps are unavailable; gaps are not filled from unaccepted source data. Media sides are reconstructed read-only through the exact-entity media projection and retained contribution/removal history. An available media value is an array of sanitized ProvenanceTimelineMediaItem objects without source attribution; [] means known empty. Reconstruction excludes uploads created after the contribution and non-displayable assets. If a formerly nonempty state has no displayable members, the side is unavailable rather than a false empty. Same-entity uploads use the protected organization asset URL; remote media display URLs preserve signed query strings and fragments. Deleted jobs, former child associations, older writes, and erased legacy reversal masks may leave gaps. `coverage.values` is `reconstructed_from_history`. Available sides contain canonical logical JSON, including explicit null; unavailable or restricted sides carry no value. Raw inputs, reasons, evidence text, and personal attribution are omitted. Timeline source-website queries and fragments are removed; media display URLs retain signed queries and fragments. Entity names retain existing prose masking, and legacy field/URL masks use pipeline compatibility. Unsupported no-field history is skipped with bounded refill; an empty page can have a non-null nextCursor when the scan budget is reached. Continue until nextCursor is null. Deploy/restart the API to enable reconstruction; no worker-write path or schema migration is needed. Every entry also includes organization_score for the parent organization at the inclusive recorded_at timestamp, including activity/session entries. ADMIN reads reconstruct retained accepted facts and evaluate the current rubric at that historical time in the same read-only snapshot. Tied timestamps share an organization state. Reconstructed scores include confidence, interval, caps and explicit history coverage; later facts and evidence are excluded. Missing history, current child associations, unavailable regional pricing and duplicate-review inputs limit reconstruction. No usable historical score facts yields unavailable, never a fabricated zero. Staff receive only state: restricted. Rubric changes may change historical scores; no cache or regional aggregate is written.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"limit","description":"Maximum entries on this page.","schema":{"type":"integer","minimum":1,"maximum":100,"default":30}},{"in":"query","name":"cursor","description":"Opaque nextCursor from the previous page for this same organization. Ordered by merge completion timestamp, entity kind, and job ID descending, preserving submillisecond precision.","schema":{"type":"string"}}],"responses":{"200":{"description":"Sanitized retained contribution history. ADMIN receives reconstructed field values and organization scores where historical inputs permit; staff receives restricted values and scores without reconstruction.","content":{"application/json":{"schema":{"type":"object","required":["data","success"],"properties":{"success":{"const":true},"data":{"type":"object","required":["organizationId","entries","nextCursor","coverage"],"properties":{"organizationId":{"type":"string","format":"uuid"},"entries":{"type":"array","items":{"type":"object","required":["id","recorded_at","entity","source","fields","state"],"properties":{"id":{"type":"string","description":"Stable entity-kind and merge-job identity."},"recorded_at":{"type":"string","format":"date-time","description":"Canonical merge completion time."},"entity":{"type":"object","required":["kind","id","name","deleted"],"properties":{"kind":{"type":"string","enum":["organization","activity","session"]},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"deleted":{"type":"boolean"}}},"source":{"type":"object","required":["kind","label"],"properties":{"kind":{"type":"string","enum":["scrape","manual_update","overseer","import","other"]},"label":{"type":"string"},"source_url":{"type":"string","format":"uri"},"batch_id":{"type":"string","format":"uuid"}}},"fields":{"type":"array","items":{"type":"object","required":["field","action","before","after"],"properties":{"field":{"type":"string","description":"Canonical field name; media gallery before/after values use arrays of ProvenanceTimelineMediaItem."},"action":{"type":"string","enum":["set","clear","contributed"],"description":"Legacy masks establish contributed fields without inventing a recorded decision."},"before":{"$ref":"#/components/schemas/ProvenanceTimelineValue"},"after":{"$ref":"#/components/schemas/ProvenanceTimelineValue"}}}},"state":{"type":"string","enum":["applied","reversed"],"description":"Historical contribution state, never a claim of current field ownership."},"organization_score":{"$ref":"#/components/schemas/ProvenanceTimelineOrganizationScore"},"reversed_at":{"type":"string","format":"date-time","description":"Completed batch reversal timestamp when retained; not an individual field restoration time."}}}},"nextCursor":{"type":["string","null"]},"coverage":{"type":"object","required":["history","children","values","reversals"],"properties":{"history":{"const":"retained_canonical_contributions"},"children":{"const":"current_associations"},"values":{"const":"reconstructed_from_history","description":"ADMIN receives reconstructed values where retained history permits; staff receives restricted sides. Storage-only fields remain restricted even for ADMIN."},"reversals":{"const":"legacy_fields_may_be_missing"}}}}}}}}}},"400":{"description":"Invalid organization ID, limit, cursor, or cursor belonging to another organization."},"403":{"description":"Requires a staff or ADMIN account; preview, machine keys, service, and delegated service access are denied."},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Read recorded camp, program, and session updates","tags":["Organization catalog"],"x-auth":"Staff or ADMIN account cookie or account API key. Only ADMIN triggers before/after reconstruction; staff receives restricted value sides. Storage-only bookkeeping remains restricted even for ADMIN. No preview, machine key, service, or delegated service access. This sanitized timeline does not grant the existing ADMIN-only raw provenance authority.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations/$ORGANIZATION_ID/provenance/timeline\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"limit=30\"","title":"Read recorded canonical updates"}],"x-internal":true}},"/api/organizations/{id}/provenance":{"get":{"description":"Returns data.organization with id and visible bookkeeping moved from normal reads. Only authorized ADMIN readers additionally receive field_provenance, source_records, merge_jobs, and relationship_jobs. Moved fields are configuration_id, external_ids, created_at, updated_at, source_created_at, field_provenance, source_records, merge_jobs, and relationship_jobs. Field provenance separates current value ownership (state, sources, value_state) from source checks and field decisions. Entries cover visible fields before sparse projection, including cleared and unknown values. A found or checked_not_found observation can exist without a value change; absence of observation means no recorded check. Sources, latest_observation, and history share a flat record shape; history is newest first. The latest observation follows observed time, while decision history follows contribution time. Omitted field_provenance means unavailable; an absent entry in an available map is unknown. Field citations are distinct from site-scoped scrape URLs.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"organization":{"$ref":"#/components/schemas/CanonicalProvenanceRow"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Canonical organization bookkeeping and authorized history"},"403":{"description":"Provenance is unavailable in preview"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Read organization bookkeeping and provenance","tags":["Organization catalog"],"x-auth":"Account cookie or header, or permitted machine key, from Starter up. Active organization members receive their existing organization detail access. Bookkeeping follows the existing field masks. Field provenance and raw histories require an ADMIN user-backed viewer, including an ADMIN-owned machine key; staff, bare service credentials, and membership upgrades do not grant this authority. All previews are denied.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations/$ORGANIZATION_ID/provenance\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read permitted organization bookkeeping and provenance"}]}},"/api/organizations/{id}/score":{"get":{"description":"Returns one canonical organization with its School’s Out organization score as pure JSON: the assembled OrganizationScoreInput, the full OrganizationScore, sources, caps, flags, field ledger, and scoring version. Organization scoring v2 combines accuracy, freshness, completeness, and activity with relative weights 20:12:13:20. Programs/funding, safety, and operator responsiveness are removed, including their input parameters, caps, and flags. Remaining Activity indicator weights are normalized by their sum. Confidence uses collected session and integrity signals alongside source depth, dated fields, and merge confidence; it affects the displayed interval without pulling the overall toward 50. This endpoint calculates the live score and returns its input/evidence separately from normal catalog reads. The embedded canonical record follows the sparse public projection.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"additionalProperties":true,"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Live score, scoring input, canonical record, scoringVersion, tier, and lockedColumns. Organization responses also include moderation and optional peers."},"400":{"description":"Invalid record UUID."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Read one live organization score","tags":["Organization catalog"],"x-auth":"Existing Starter+ score access and field masks apply. Active organization membership retains its scoped detail access.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/organizations/$ORGANIZATION_ID/score\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read organization live score detail"}]}},"/api/sessions/scores":{"get":{"description":"Returns score summaries for up to 24 distinct canonical sessions from ?ids=UUID,UUID with scores, missing, scoringVersion, and tier. The default and cached=false calculate live scores. Optional cached=true returns persisted summaries without evidence reads or calculation; scores and missing follow request order, and missing caches never trigger live fallback. Cached reads exclude deleted and blacklisted records even for moderation readers and deny all previews. Both modes retain Starter+ access. cached accepts one exact true or false value; malformed or repeated values return 400.","parameters":[{"description":"Comma-separated distinct record UUIDs, up to 24. UUID case is ignored.","in":"query","name":"ids","required":true,"schema":{"type":"string"}},{"description":"One exact true or false value. true reads persisted summaries; omitted or false calculates live summaries.","in":"query","name":"cached","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"missing":{"items":{"format":"uuid","type":"string"},"type":"array"},"scores":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"scoringVersion":{"type":"string"},"tier":{"type":"string"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Score summaries and IDs with no available result. Cached mode never recalculates missing scores."},"400":{"description":"Missing, invalid, or excessive IDs, or malformed/repeated cached values."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"403":{"description":"Cached score summaries are unavailable in preview."},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Read session score summaries","tags":["Organization catalog"],"x-auth":"Starter+ account cookie, account header, or permitted machine key. Cached reads deny all previews.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/sessions/scores\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\" \\\n  --data-urlencode \"ids=$SESSION_ID\" \\\n  --data-urlencode \"cached=true\"","title":"Read session cached summaries"}]}},"/api/sessions/{id}/provenance":{"get":{"description":"Returns data.session with id and visible bookkeeping moved from normal reads. Only authorized ADMIN readers additionally receive field_provenance, source_records, merge_jobs, and relationship_jobs. Moved fields are configuration_id, external_ids, created_at, updated_at, source_created_at, field_provenance, source_records, merge_jobs, and relationship_jobs. Field provenance separates current value ownership (state, sources, value_state) from source checks and field decisions. Entries cover visible fields before sparse projection, including cleared and unknown values. A found or checked_not_found observation can exist without a value change; absence of observation means no recorded check. Sources, latest_observation, and history share a flat record shape; history is newest first. The latest observation follows observed time, while decision history follows contribution time. Omitted field_provenance means unavailable; an absent entry in an available map is unknown. Field citations are distinct from site-scoped scrape URLs.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"properties":{"session":{"$ref":"#/components/schemas/CanonicalProvenanceRow"}},"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Canonical session bookkeeping and authorized history"},"403":{"description":"Provenance is unavailable in preview"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Read session bookkeeping and provenance","tags":["Organization catalog"],"x-auth":"Account cookie or header, or permitted machine key, from Starter up. Bookkeeping follows the existing field masks. Field provenance and raw histories require an ADMIN user-backed viewer, including an ADMIN-owned machine key; staff, bare service credentials, and membership upgrades do not grant this authority. All previews are denied.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/sessions/$SESSION_ID/provenance\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read permitted session bookkeeping and provenance"}]}},"/api/sessions/{id}/score":{"get":{"description":"Returns one canonical session with its School’s Out session score as pure JSON: the assembled SessionScoreInput (dates, availability, sources, and its activity's and camp's scores), the full score whose bookability criterion carries no weight once the session has ended, and the scoring version. Registration evidence reads the session-owned registration dates; existing status precedence is unchanged. This endpoint calculates the live score and returns its input/evidence separately from normal catalog reads. The embedded canonical record follows the sparse public projection.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"additionalProperties":true,"type":"object"},"success":{"const":true}},"type":"object"}}},"description":"Live score, scoring input, canonical record, scoringVersion, tier, and lockedColumns. Organization responses also include moderation and optional peers."},"400":{"description":"Invalid record UUID."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PlanRequired"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/ServerError"}},"summary":"Read one live session score","tags":["Organization catalog"],"x-auth":"Existing Starter+ score access and field masks apply. Active organization membership retains its scoped detail access.","x-curl-examples":[{"code":"curl --get \"https://apis.schoolsoutapp.com/api/sessions/$SESSION_ID/score\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_API_KEY\"","title":"Read session live score detail"}]}},"/api/overseer/messages":{"post":{"description":"Queues a staff-authored request for the next worker turn without editing standing instructions or interrupting the current turn. Supply a canonical UUID requestId; retry identical requestId, expectedRevision and text after an uncertain result to retrieve its durable receipt, even after the active revision changes. Reusing an ID for different input returns 409. New stale requests return 409 with the current snapshot. The first request may initialize an empty revision when expectedRevision is zero. The current configuration editor remains the execution authority; the submitting operator is retained as message attribution. A maximum of 100 requests may be pending. Requests are delivered only after a valid successful agent turn; failed attempts retain them for recovery using committed action history. Requests arriving during a turn remain queued for the next turn. Replacing the configuration or clearing memory cancels outstanding requests visibly. Events user_message, message_delivered and message_cancelled identify their requestId; user_message also contains text. Delivered is transport acknowledgment, not proof of requested work completion. The saved owner is reauthorized before inference and tools; a message never takes over execution ownership. Revoking a sender after acceptance does not retroactively cancel the request. Unfinished delivered work can continue through the same revision checkpoint and native thread. A new stale submission includes top-level outcome=rejected and messageRejection={requestId,expectedRevision}; because historical receipt lookup preceded the monotonic revision check under one lock, the exact request cannot later be accepted. An uncertain client may release its retry only for a matching marker or a durable receipt. A generic 409 does not prove delivery outcome. Requests may be queued while paused; enqueue preserves the pause state and they wait for an explicit resume.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"expectedRevision":{"type":"integer","minimum":0},"requestId":{"type":"string","format":"uuid"},"text":{"type":"string","minLength":1,"description":"Nonblank request, at most 16384 UTF-8 bytes. Original text is retained in its durable receipt."}},"required":["expectedRevision","requestId","text"]}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerMessage"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Durable request receipt, including an identical earlier submission."},"400":{"description":"Missing, invalid, or unsupported request input."},"401":{"description":"Authentication required."},"403":{"description":"Current identity is not a user-backed staff or ADMIN operator, or the browser mutation lacks a trusted origin and session-bound CSRF token."},"409":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"error":{"const":true},"message":{"type":"string"},"success":{"const":false},"outcome":{"type":"string","const":"rejected","description":"Present with messageRejection only when the exact stale submission was not accepted and can never be accepted later."},"messageRejection":{"type":"object","additionalProperties":false,"properties":{"requestId":{"type":"string","format":"uuid"},"expectedRevision":{"type":"integer","minimum":0}},"required":["requestId","expectedRevision"],"description":"Definitive rejection identity after historical receipt lookup and stale revision comparison under the singleton lock. Match both fields before releasing an uncertain send."}},"required":["error","message"],"type":"object"}}},"description":"The current revision changed, or requestId was reused for different input. Current snapshot is included for a revision conflict."}},"security":[{"ApiKeyAuth":[]}],"summary":"Queue a one-off Overseer request","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN identity. Account credentials and machine keys belonging to eligible users are accepted; a bare service credential is not. Intelligence uses its signed session cookie; cookie POST requests require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"title":"Queue a one-off request without changing instructions","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/overseer/messages\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"expectedRevision\":12,\"requestId\":\"eb4b5d5a-87b0-4cb4-a4f8-0e874584396a\",\"text\":\"Summarize the outstanding Washington reviews.\"}'"}],"x-internal":true}},"/api/overseer/pause":{"post":{"description":"Sets the global desired pause state using expectedRevision and expectedPauseVersion. Both must match the current snapshot, otherwise 409 returns the current snapshot. An unchanged desired state with matching versions is a no-op; an actual change increments only pauseVersion. Pause immediately fences the active turn and asks the supervisor to stop and join its native process and tools; existing execution occupancy remains until cleanup releases it or its lease expires. Instructions, tool controls, native thread, checkpoint, queued messages, editor authority, underlying work state and wake/backoff schedule are preserved. Resume restores eligibility under that schedule; it does not start an API-owned worker or bypass backoff. Save, message enqueue, review feedback and clear-memory never implicitly resume. Pause is supported before any saved instruction and does not create a revision. Existing human review approvals and already-dispatched child jobs remain independent. Paused execution creates no new scheduled progress reports or notification delivery claims, but preserves due timestamps and pending notices; already-claimed delivery may finish under its existing fence. pause_changed events contain paused and pauseVersion when a saved revision exists. After an uncertain response, read the current snapshot before a new explicit control request; do not automatically retry against refreshed versions.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"expectedRevision":{"type":"integer","minimum":0},"expectedPauseVersion":{"type":"integer","minimum":0},"paused":{"type":"boolean"}},"required":["expectedRevision","expectedPauseVersion","paused"]}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"success":{"const":true}},"required":["data","success"],"type":"object"}}},"description":"Current snapshot after the requested pause state was applied or was already current."},"400":{"description":"Missing, invalid, or unsupported request input."},"401":{"description":"Authentication required."},"403":{"description":"Current identity is not a user-backed staff or ADMIN operator, or the browser mutation lacks a trusted origin and session-bound CSRF token."},"409":{"content":{"application/json":{"schema":{"properties":{"data":{"$ref":"#/components/schemas/OverseerSnapshot"},"error":{"const":true},"message":{"type":"string"},"success":{"const":false}},"required":["data","success","message"],"type":"object"}}},"description":"Instruction revision or pause version changed. Review the current snapshot before a new explicit request."}},"security":[{"ApiKeyAuth":[]}],"summary":"Pause or resume Overseer execution","tags":["Internal Overseer"],"x-auth":"Current user-backed staff or ADMIN identity. Account credentials and machine keys belonging to eligible users are accepted; a bare service credential is not. Intelligence uses its signed session cookie; cookie POST requests require a trusted origin and session-bound CSRF token.","x-curl-examples":[{"title":"Pause the configuration reviewed at revision 12 and pause version 3","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/overseer/pause\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"expectedRevision\":12,\"expectedPauseVersion\":3,\"paused\":true}'"}],"x-internal":true}},"/api/ingestion/crawler-campaigns":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"GET crawler campaigns","description":"List or create durable mass-crawl jobs. Creation accepts location, nearby_locations, providers, confidence_threshold, follow_aggregators and a stable idempotency_key. Retries retain the original creation identity after settings edits. The complete search plan is scoped to explicit localities, including neighborhood searches for Portland, Oregon.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"x-curl-examples":[{"title":"GET crawler campaigns","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]},"post":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"POST crawler campaigns","description":"List or create durable mass-crawl jobs. Creation accepts location, nearby_locations, providers, confidence_threshold, follow_aggregators and a stable idempotency_key. Retries retain the original creation identity after settings edits. The complete search plan is scoped to explicit localities, including neighborhood searches for Portland, Oregon.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"location":{"type":"string"},"idempotency_key":{"type":"string"},"providers":{"type":"array","items":{"type":"string"}},"nearby_locations":{"type":"array","items":{"type":"string"}}},"required":["location","idempotency_key"]}}}},"x-curl-examples":[{"title":"POST crawler campaigns","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"location\":\"Portland, Oregon\",\"idempotency_key\":\"portland-camps-2026\",\"providers\":[\"google\"]}'"}]}},"/api/ingestion/crawler-campaigns/{id}":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"GET crawler campaigns","description":"Read current-generation search, crawl, resolved Trident classification and unresolved counts. Successful historical crawls are reused. No request owns worker lifetime. Counts additionally include informational location_pending_urls, location_unresolved_urls and location_mismatch_urls; geography never excludes an eligible camp. Location counts describe actual historical records only; missing checks are not pending work. queued_urls excludes acquisition suppressed by saved site qualification or unrelated link expansion. site_qualified_urls and discovery_only_urls count those previously requested, unacquired URLs separately; all discovery records remain saved. Use include_counts=false for immediate navigation and request counts separately. Geography is historical metadata; no new location work is scheduled.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}},{"name":"include_counts","in":"query","schema":{"type":"boolean","default":true},"description":"False reads settings without computing frontier counts; counts fields are zero in this fast metadata response."}],"x-curl-examples":[{"title":"GET crawler campaigns","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/ingestion/crawler-campaigns/{id}/control":{"post":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"POST crawler campaigns","description":"Pause, resume, or rerun. Provider account failures automatically pause active mass-crawl jobs and expose campaign.provider_block with provider (jev, proxy, openai or capmonster) and a safe code. Restore account access or funds before resume; resume clears the block and continues the same generation using saved progress. Rerun requires a paused/completed campaign and expected_generation, making uncertain retries idempotent. It retains every saved URL and discovery path.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"action":{"type":"string","enum":["pause","resume","rerun"]},"expected_generation":{"type":"integer","minimum":1}},"required":["action"]}}}},"x-curl-examples":[{"title":"POST crawler campaigns","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/control\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"action\":\"pause\",\"expected_generation\":1}'"}]}},"/api/ingestion/crawler-campaigns/{id}/urls":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"GET crawler campaigns","description":"Read up to 100 saved URLs after an optional decimal after ID, with crawl status, mass-crawl assessment, and historical source metadata. crawl_skip_reason is site_qualified, discovery_only or null; it distinguishes preserved URLs that need no acquisition from the active crawl queue. Policy 9 classification_details.version=2 includes source_analysis: named organizations, individual offerings, publisher relationships, source types, availability, seasons, grounded citations and cross-page identity links, joint uncalibrated confidence, and eligibility review. Old policy records remain retained. evidence_status distinguishes available, not_saved, acquisition_failed and explicit unusable-evidence reasons; ever_classified distinguishes no historical evaluation; classification_error retains operational errors separately from source verdicts. Each URL includes nullable location_check for an actual historical check: status (pending/running/retry/completed), projected decision (pending/matched/mismatch/unresolved) and nullable saved assessment. Assessments retain decision, confidence, requested locations, reason, model, original model responses and grounded evidence (URL, exact excerpt, content_sha256, fetched_at). Compact responses include next_after (decimal source URL ID or null), the projected confidence_threshold, trident_status (qualified, irrelevant, unresolved), organization_count and offering_count. Follow next_after for another page of at most 100 results.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}},{"name":"after","in":"query","schema":{"type":"string"}},{"name":"compact","in":"query","schema":{"type":"boolean","default":false},"description":"Return bounded summaries without model response bodies, citations, source facts or confidence replay variants. Fetch URL details on demand."}],"x-curl-examples":[{"title":"GET crawler campaigns","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/urls\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/ingestion/crawler-campaigns/{id}/discoveries":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"GET crawler campaigns","description":"Read up to 100 discovery edges after an optional decimal after ID. Without url_id, results cover the selected campaign across its runs. With url_id, incoming edges cover every mass-crawl job that recorded the shared URL. campaign_id, campaign_location, generation and parent_url_id retain the path provenance. settings_revision links each new discovery to the immutable settings snapshot used by its search or expansion. Older discoveries have null when their original settings cannot be recovered; campaign_location uses the recorded location when known.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}},{"name":"after","in":"query","schema":{"type":"string"}},{"name":"url_id","in":"query","schema":{"type":"string"}}],"x-curl-examples":[{"title":"GET crawler campaigns","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/discoveries\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/ingestion/crawler-campaigns/{id}/searches":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"GET crawler campaigns","description":"Read up to 100 term/provider states after an optional decimal after ID, with attempts, pages fetched and completion reasons. Blocks remain retryable instead of exhausted.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}},{"name":"after","in":"query","schema":{"type":"string"}}],"x-curl-examples":[{"title":"GET crawler campaigns","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/searches\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/ingestion/crawler-campaigns/search-plan":{"post":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"Preview a mass-crawl search plan","description":"Generate the full deduplicated term list and query/provider count without creating a job or contacting search providers. The response contains data.search_plan with terms, providers and search_count. Cookie requests require CSRF.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie POST requests.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"location":{"type":"string","description":"Explicit search locality, for example Portland, Oregon."},"nearby_locations":{"type":"array","items":{"type":"string"},"maxItems":29,"description":"Additional explicit localities."},"providers":{"type":"array","minItems":1,"items":{"type":"string","enum":["google","bing","duckduckgo","brave","startpage","qwant"]},"description":"Search providers included in the plan."}},"required":["location","nearby_locations","providers"]}}}},"x-curl-examples":[{"title":"Preview a mass-crawl search plan","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/search-plan\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"location\":\"Portland, Oregon\",\"nearby_locations\":[],\"providers\":[\"google\"]}'"}]}},"/api/ingestion/crawler-campaigns/{id}/settings":{"post":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"Update mass-crawl settings","description":"Apply complete live settings with revision conflict protection. Completed matching searches and saved URL evidence are retained. Paused jobs stay paused; changing the search plan can reopen completed jobs. Returns data.campaign; stale revisions return 409. Every accepted edit records an immutable timestamped settings snapshot. Location changes reuse fetched evidence and queue a geographic check for the new area; confidence changes reuse saved scores.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie POST requests.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"location":{"type":"string","description":"Explicit search locality, for example Portland, Oregon."},"nearby_locations":{"type":"array","items":{"type":"string"},"maxItems":29,"description":"Additional explicit localities."},"providers":{"type":"array","minItems":1,"items":{"type":"string","enum":["google","bing","duckduckgo","brave","startpage","qwant"]},"description":"Search providers included in the plan."},"confidence_threshold":{"type":"number","minimum":0,"maximum":1,"description":"Acceptance threshold applied to retained classification evidence."},"follow_aggregators":{"type":"boolean","description":"Discover outgoing URLs from saved aggregator pages."},"expected_revision":{"type":"integer","minimum":1,"description":"The settings revision last read by this operator."}},"required":["location","nearby_locations","providers","confidence_threshold","follow_aggregators","expected_revision"]}}}},"x-curl-examples":[{"title":"Update mass-crawl settings","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/settings\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"location\":\"Portland, Oregon\",\"nearby_locations\":[],\"providers\":[\"google\"],\"confidence_threshold\":0.8,\"follow_aggregators\":true,\"expected_revision\":1}'"}]}},"/api/ingestion/crawler-campaigns/{id}/homepages":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"Read vetted camp homepages","description":"Read deduplicated first-party camp homepages at the saved confidence threshold. Any location and season qualifies; geographic checks are retained historical metadata and never gate eligibility. Each includes the current assessment and source_url_id/source_url/historical_source for detail navigation. The default full response retains classification_details; compact=true omits it and paginates after deduplication. Compact responses include next_after (source URL ID or null), trident_status, organization_count and offering_count.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie POST requests.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}},{"name":"compact","in":"query","schema":{"type":"boolean","default":false},"description":"Return bounded summaries without model response bodies, citations, source facts or confidence replay variants. Fetch URL details on demand."},{"name":"after","in":"query","schema":{"type":"string"},"description":"Exclusive source URL cursor for compact=true."}],"x-curl-examples":[{"title":"Read vetted camp homepages","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/homepages\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/ingestion/crawler-campaigns/{id}/search-plan":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"Read the saved mass-crawl search plan","description":"Read all enabled current-generation terms, including completed searches, without truncation or regeneration. Returns data.search_plan with terms, providers, search_count and settings_revision from one database snapshot.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie POST requests.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}}],"x-curl-examples":[{"title":"Read the saved mass-crawl search plan","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/search-plan\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/ingestion/crawler-campaigns/{id}/settings-history":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"Read immutable mass-crawl settings history","description":"Returns up to 100 saved settings revisions in descending order. Pass before=<oldest revision> for the next page. Each entry identifies the run, timestamp, operator when known, reason and complete settings snapshot. A baseline entry marks the retained current state for jobs created before history existed; earlier settings are not invented.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["history"],"properties":{"history":{"type":"array","items":{"type":"object","required":["revision","generation","recorded_at","actor_id","reason","settings"],"properties":{"revision":{"type":"integer","minimum":1},"generation":{"type":"integer","minimum":1},"recorded_at":{"type":"string","format":"date-time"},"actor_id":{"type":["string","null"],"format":"uuid"},"reason":{"type":"string","enum":["created","settings","control","baseline"]},"settings":{"type":"object","additionalProperties":false,"properties":{"location":{"type":"string","description":"Explicit search locality, for example Portland, Oregon."},"nearby_locations":{"type":"array","items":{"type":"string"},"maxItems":29,"description":"Additional explicit localities."},"providers":{"type":"array","minItems":1,"items":{"type":"string","enum":["google","bing","duckduckgo","brave","startpage","qwant"]},"description":"Search providers included in the plan."},"confidence_threshold":{"type":"number","minimum":0,"maximum":1,"description":"Acceptance threshold applied to retained classification evidence."},"follow_aggregators":{"type":"boolean","description":"Discover outgoing URLs from saved aggregator pages."},"status":{"type":"string","enum":["active","paused","completed"]},"plan_version":{"type":"integer","minimum":1}},"required":["location","nearby_locations","providers","confidence_threshold","follow_aggregators","status","plan_version"]}}}}}}}}}}},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}},{"name":"before","in":"query","required":false,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}}],"x-curl-examples":[{"title":"Read immutable mass-crawl settings history","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/00000000-0000-4000-8000-000000000001/settings-history\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/users/viewer/feed":{"get":{"tags":["Internal family profiles"],"x-internal":true,"summary":"Read the family feed","description":"Read the current immutable published edition, generating it on first request, or read a previously published edition by date and slot. Scores and ranking evidence remain private.","x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","security":[{"AccountCredential":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"edition":{"$ref":"#/components/schemas/FamilyFeedEdition"},"current":{"$ref":"#/components/schemas/FamilyFeedEditionKey"},"editions":{"type":"array","items":{"$ref":"#/components/schemas/FamilyFeedEditionKey"}}},"required":["edition","current","editions"],"additionalProperties":false}},"required":["success","data"],"additionalProperties":false}}}},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"},"409":{"description":"Household search area is required to publish the first edition."}},"x-curl-examples":[{"title":"Read the family feed","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/users/viewer/feed\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}],"parameters":[{"name":"date","in":"query","schema":{"type":"string","format":"date"},"description":"Edition date, used with slot."},{"name":"slot","in":"query","schema":{"type":"string","enum":["morning","evening"]},"description":"Edition slot, used with date."}]}},"/api/users/viewer/feed/posts/{postId}/signal":{"put":{"tags":["Internal family profiles"],"x-internal":true,"summary":"Set a feed post signal","description":"Set, change or clear the signed-in adult's own signal. A post owned by another account returns 404.","x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","security":[{"AccountCredential":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"postId":{"type":"string","format":"uuid"},"signal":{"type":["string","null"],"enum":["like","dislike","dont_show_again",null]}},"required":["postId","signal"],"additionalProperties":false}},"required":["success","data"],"additionalProperties":false}}}},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"signal":{"type":["string","null"],"enum":["like","dislike","dont_show_again",null]}},"required":["signal"],"additionalProperties":false},"example":{"signal":"like"}}}},"x-curl-examples":[{"title":"Set a feed post signal","code":"curl -X PUT \"https://apis.schoolsoutapp.com/api/users/viewer/feed/posts/00000000-0000-4000-8000-000000000001/signal\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"signal\":\"like\"}'"}],"parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/users/viewer/feed/camp-views":{"post":{"tags":["Internal family profiles"],"x-internal":true,"summary":"Record a camp page view","description":"Record the signed-in adult's dwell time on an organization, activity or session. This is private family interest evidence.","x-auth":"Current account cookie or account credential only. Machine keys, investor previews and delegated service requests are rejected regardless of plan, billing team, staff or ADMIN level. Cookie mutations require CSRF from a trusted or API_ASSISTANT_ORIGINS origin. Records are private to the signed-in adult; sharing a child never shares them.","security":[{"AccountCredential":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"recorded":{"type":"boolean","const":true}},"required":["recorded"],"additionalProperties":false}},"required":["success","data"],"additionalProperties":false}}}},"400":{"description":"Invalid input"},"401":{"description":"Current account required"},"404":{"description":"Record not found for this account"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetKind":{"type":"string","enum":["organization","activity","session"]},"targetId":{"type":"string","format":"uuid"},"dwellSeconds":{"type":"integer","minimum":0,"maximum":86400}},"required":["targetKind","targetId","dwellSeconds"],"additionalProperties":false},"example":{"targetKind":"organization","targetId":"00000000-0000-4000-8000-000000000001","dwellSeconds":30}}}},"x-curl-examples":[{"title":"Record a camp page view","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/users/viewer/feed/camp-views\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"targetKind\":\"organization\",\"targetId\":\"00000000-0000-4000-8000-000000000001\",\"dwellSeconds\":30}'"}]}},"/api/hallpass/runs":{"get":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"List staff runs","description":"The 50 newest runs by any staff member, as last read. Read a run to refresh it.","responses":{"200":{"description":"The newest runs.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["runs"],"properties":{"runs":{"type":"array","items":{"$ref":"#/components/schemas/HallPassRun"}}}}}},"example":{"success":true,"data":{"runs":[{"id":"0c7e5a2b-9d14-4f6a-8b3e-2a1d5c9f7e40","kind":"general","summary":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","rehearsal":false,"maxSpend":{"amountCents":6000,"currency":"USD"},"autoAcceptDecisions":false,"requesterUserId":"4b2e7c1a-9d3f-4e8b-a6c5-1f0d2e3c4b5a","request":{"instruction":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","startUrl":"https://greenbowl.example/order","sessionId":null,"merchant":null},"state":"awaiting_decision","refusal":null,"mode":"automatic","stage":null,"hold":null,"decision":{"decisionId":"2a6c9e1b-4d8f-4b3a-9c7e-5f1d0a8b3c26","code":"confirm_total","message":"Pay USD 48.20 to Green Bowl Kitchen for two dinner bowls?","options":[{"optionId":"confirm","label":"Pay USD 48.20","total":{"amountCents":4820,"currency":"USD"}}],"proposedOptionId":null,"expiresAt":"2026-10-09T19:00:00Z"},"decisions":[],"receipt":null,"failure":null,"uncertainty":null,"pollAfterMs":15000,"deadlineAt":"2026-10-09T19:00:00Z","createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:02:00Z"}]}}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"List staff runs","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/hallpass/runs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]},"post":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Start a staff run","description":"Starts a Hallpass task and returns it as Hallpass first reports it. A run with no `kind` is general; a run places the order by default, spending up to `maxSpend` or the staff cap (general runs still wait for staff to confirm the exact total); `rehearsal` stops at the checkout total and orders nothing. A camp booking run reads its target from the catalog session.","responses":{"201":{"description":"The run was created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["run"],"properties":{"run":{"$ref":"#/components/schemas/HallPassRun"}}}}},"example":{"success":true,"data":{"run":{"id":"0c7e5a2b-9d14-4f6a-8b3e-2a1d5c9f7e40","kind":"general","summary":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","rehearsal":false,"maxSpend":{"amountCents":6000,"currency":"USD"},"autoAcceptDecisions":false,"requesterUserId":"4b2e7c1a-9d3f-4e8b-a6c5-1f0d2e3c4b5a","request":{"instruction":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","startUrl":"https://greenbowl.example/order","sessionId":null,"merchant":null},"state":"awaiting_decision","refusal":null,"mode":"automatic","stage":null,"hold":null,"decision":{"decisionId":"2a6c9e1b-4d8f-4b3a-9c7e-5f1d0a8b3c26","code":"confirm_total","message":"Pay USD 48.20 to Green Bowl Kitchen for two dinner bowls?","options":[{"optionId":"confirm","label":"Pay USD 48.20","total":{"amountCents":4820,"currency":"USD"}}],"proposedOptionId":null,"expiresAt":"2026-10-09T19:00:00Z"},"decisions":[],"receipt":null,"failure":null,"uncertainty":null,"pollAfterMs":15000,"deadlineAt":"2026-10-09T19:00:00Z","createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:02:00Z"}}}}}},"200":{"description":"The existing run for this idempotency key, returned because the request was a resend.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["run"],"properties":{"run":{"$ref":"#/components/schemas/HallPassRun"}}}}},"example":{"success":true,"data":{"run":{"id":"0c7e5a2b-9d14-4f6a-8b3e-2a1d5c9f7e40","kind":"general","summary":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","rehearsal":false,"maxSpend":{"amountCents":6000,"currency":"USD"},"autoAcceptDecisions":false,"requesterUserId":"4b2e7c1a-9d3f-4e8b-a6c5-1f0d2e3c4b5a","request":{"instruction":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","startUrl":"https://greenbowl.example/order","sessionId":null,"merchant":null},"state":"awaiting_decision","refusal":null,"mode":"automatic","stage":null,"hold":null,"decision":{"decisionId":"2a6c9e1b-4d8f-4b3a-9c7e-5f1d0a8b3c26","code":"confirm_total","message":"Pay USD 48.20 to Green Bowl Kitchen for two dinner bowls?","options":[{"optionId":"confirm","label":"Pay USD 48.20","total":{"amountCents":4820,"currency":"USD"}}],"proposedOptionId":null,"expiresAt":"2026-10-09T19:00:00Z"},"decisions":[],"receipt":null,"failure":null,"uncertainty":null,"pollAfterMs":15000,"deadlineAt":"2026-10-09T19:00:00Z","createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:02:00Z"}}}}}},"400":{"description":"The details are invalid, or `maxSpend` is above the deployment’s cap.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Full orders are switched off in this deployment: the staff spending cap is 0. Start a rehearsal, or raise HALLPASS_STAFF_MAX_SPEND_CENTS.","data":null}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}},"404":{"description":"The camp booking’s session is not in the catalog.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"That session is not in the catalog.","data":null}}}},"409":{"description":"This idempotency key was already used for different details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"This idempotency key was already used for a different run.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Start a staff run","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/hallpass/runs\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"idempotencyKey\": \"5d3c1b2a-7e6f-4a8b-9c0d-1e2f3a4b5c6d\", \"maxSpend\": {\"amountCents\": 6000, \"currency\": \"USD\"}, \"general\": {\"instruction\": \"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.\", \"startUrl\": \"https://greenbowl.example/order\", \"subjects\": [{\"role\": \"recipient\", \"fields\": {\"full_name\": \"Sam Rivera\", \"street_address\": \"18 Alder Lane\", \"postal_code\": \"97214\"}}]}}'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunInput"},"example":{"idempotencyKey":"5d3c1b2a-7e6f-4a8b-9c0d-1e2f3a4b5c6d","maxSpend":{"amountCents":6000,"currency":"USD"},"general":{"instruction":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","startUrl":"https://greenbowl.example/order","subjects":[{"role":"recipient","fields":{"full_name":"Sam Rivera","street_address":"18 Alder Lane","postal_code":"97214"}}]}}}}}}},"/api/hallpass/runs/{runId}":{"get":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Get a staff run","description":"Returns the run after resending a task Hallpass has not acknowledged, or reading Hallpass’s status while it can still change. A Hallpass outage returns the run as last read.","responses":{"200":{"description":"The run.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["run"],"properties":{"run":{"$ref":"#/components/schemas/HallPassRun"}}}}},"example":{"success":true,"data":{"run":{"id":"0c7e5a2b-9d14-4f6a-8b3e-2a1d5c9f7e40","kind":"general","summary":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","rehearsal":false,"maxSpend":{"amountCents":6000,"currency":"USD"},"autoAcceptDecisions":false,"requesterUserId":"4b2e7c1a-9d3f-4e8b-a6c5-1f0d2e3c4b5a","request":{"instruction":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","startUrl":"https://greenbowl.example/order","sessionId":null,"merchant":null},"state":"awaiting_decision","refusal":null,"mode":"automatic","stage":null,"hold":null,"decision":{"decisionId":"2a6c9e1b-4d8f-4b3a-9c7e-5f1d0a8b3c26","code":"confirm_total","message":"Pay USD 48.20 to Green Bowl Kitchen for two dinner bowls?","options":[{"optionId":"confirm","label":"Pay USD 48.20","total":{"amountCents":4820,"currency":"USD"}}],"proposedOptionId":null,"expiresAt":"2026-10-09T19:00:00Z"},"decisions":[],"receipt":null,"failure":null,"uncertainty":null,"pollAfterMs":15000,"deadlineAt":"2026-10-09T19:00:00Z","createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:02:00Z"}}}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}},"404":{"description":"No run has this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Run not found.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Get a staff run","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/hallpass/runs/$RUN_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/hallpass/runs/{runId}/decisions/{decisionId}":{"post":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Answer a staff run’s decision","description":"Accepting resumes the task; accepting a `confirm_total` decision lets Hallpass pay exactly that total. Declining ends the run. Only a signed-in staff or ADMIN account answers: a named machine key gets 403, because accepting can approve a payment.","responses":{"200":{"description":"The run after the answer.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["run"],"properties":{"run":{"$ref":"#/components/schemas/HallPassRun"}}}}},"example":{"success":true,"data":{"run":{"id":"0c7e5a2b-9d14-4f6a-8b3e-2a1d5c9f7e40","kind":"general","summary":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","rehearsal":false,"maxSpend":{"amountCents":6000,"currency":"USD"},"autoAcceptDecisions":false,"requesterUserId":"4b2e7c1a-9d3f-4e8b-a6c5-1f0d2e3c4b5a","request":{"instruction":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","startUrl":"https://greenbowl.example/order","sessionId":null,"merchant":null},"state":"awaiting_decision","refusal":null,"mode":"automatic","stage":null,"hold":null,"decision":{"decisionId":"2a6c9e1b-4d8f-4b3a-9c7e-5f1d0a8b3c26","code":"confirm_total","message":"Pay USD 48.20 to Green Bowl Kitchen for two dinner bowls?","options":[{"optionId":"confirm","label":"Pay USD 48.20","total":{"amountCents":4820,"currency":"USD"}}],"proposedOptionId":null,"expiresAt":"2026-10-09T19:00:00Z"},"decisions":[],"receipt":null,"failure":null,"uncertainty":null,"pollAfterMs":15000,"deadlineAt":"2026-10-09T19:00:00Z","createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:02:00Z"}}}}}},"400":{"description":"The answer is invalid or names an option the decision didn’t offer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Choose one of the offered options.","data":null}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}},"404":{"description":"No run has this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Run not found.","data":null}}}},"409":{"description":"The decision is no longer waiting for an answer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"That decision is no longer waiting for an answer.","data":null}}}},"503":{"description":"Hallpass did not take the answer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"The answer could not be sent. Try again.","data":null}}}}},"security":[{"AccountCredential":[]}],"x-auth":"Current signed-in staff or ADMIN account acting as itself: the Intelligence session cookie or that account’s credential. Machine keys, previews, bare service credentials and delegated service requests are rejected, so every run names the person who started it. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when the API has HALLPASS_URL and HALLPASS_SERVICE_TOKEN; otherwise 404.","x-curl-examples":[{"title":"Confirm the total","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/hallpass/runs/$RUN_ID/decisions/$DECISION_ID\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"outcome\": \"accept\", \"optionId\": \"confirm\"}'"}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"decisionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["outcome"],"properties":{"outcome":{"type":"string","enum":["accept","decline"]},"optionId":{"type":["string","null"],"description":"Required to accept."},"answer":{"type":["string","null"],"minLength":1,"maxLength":2000,"description":"Your typed answer. Required to accept an `answer_required` decision; omit it otherwise."}}},"example":{"outcome":"accept","optionId":"confirm"}}}}}},"/api/hallpass/runs/{runId}/cancel":{"post":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Cancel a staff run","description":"Cancels the run until Hallpass has started paying.","responses":{"200":{"description":"The run after the cancellation.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["run"],"properties":{"run":{"$ref":"#/components/schemas/HallPassRun"}}}}},"example":{"success":true,"data":{"run":{"id":"0c7e5a2b-9d14-4f6a-8b3e-2a1d5c9f7e40","kind":"general","summary":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","rehearsal":false,"maxSpend":{"amountCents":6000,"currency":"USD"},"autoAcceptDecisions":false,"requesterUserId":"4b2e7c1a-9d3f-4e8b-a6c5-1f0d2e3c4b5a","request":{"instruction":"Order dinner for two from Green Bowl Kitchen, delivered by 6:30 pm.","startUrl":"https://greenbowl.example/order","sessionId":null,"merchant":null},"state":"awaiting_decision","refusal":null,"mode":"automatic","stage":null,"hold":null,"decision":{"decisionId":"2a6c9e1b-4d8f-4b3a-9c7e-5f1d0a8b3c26","code":"confirm_total","message":"Pay USD 48.20 to Green Bowl Kitchen for two dinner bowls?","options":[{"optionId":"confirm","label":"Pay USD 48.20","total":{"amountCents":4820,"currency":"USD"}}],"proposedOptionId":null,"expiresAt":"2026-10-09T19:00:00Z"},"decisions":[],"receipt":null,"failure":null,"uncertainty":null,"pollAfterMs":15000,"deadlineAt":"2026-10-09T19:00:00Z","createdAt":"2026-10-09T17:00:00Z","updatedAt":"2026-10-09T17:02:00Z"}}}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}},"404":{"description":"No run has this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Run not found.","data":null}}}},"409":{"description":"Hallpass has not acknowledged the run yet, or it is already finished.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"This run is already finished.","data":null}}}},"503":{"description":"Hallpass did not take the cancellation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"The cancellation could not be sent. Try again.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Cancel a staff run","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/hallpass/runs/$RUN_ID/cancel\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/hallpass/plans":{"post":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Plan a staff run","description":"Reads a request the way Hallpass would, without starting anything: send `sessionId` to plan a camp booking, or a `startUrl` or instruction to find catalog sessions on that site. Use the answer to choose the run's kind.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"instruction":{"type":"string"},"startUrl":{"type":"string"},"sessionId":{"type":"string","format":"uuid"}}},"example":{"startUrl":"https://lakeside.example/register"}}}},"responses":{"200":{"description":"The plan.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["plan"],"properties":{"plan":{"$ref":"#/components/schemas/HallPassPlan"}}}}},"example":{"success":true,"data":{"plan":{"kind":"general","reason":"This page belongs to Lakeside Science Camp, which School’s Out lists. Choose one of its sessions to book it as a camp booking, or keep it as a general task.","sessions":[{"sessionId":"c3a9e1f2-6d4b-4a8c-b2e7-0f5d9c1a3b48","sessionName":"Robotics Week","organizationName":"Lakeside Science Camp","startDate":"2027-07-12","endDate":"2027-07-16"}],"missing":[]}}}}}},"400":{"description":"The body has an unknown property or an invalid session ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"sessionId must be a UUID.","data":null}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}},"404":{"description":"The session is not in the catalog.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"That session is not in the catalog.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Plan a staff run","code":"curl -X POST \"https://apis.schoolsoutapp.com/api/hallpass/plans\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"startUrl\": \"https://lakeside.example/register\"}'"}]}},"/api/hallpass/runs/{runId}/activity":{"get":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Read a staff run's activity","description":"Returns up to 200 lines of the run's live log after `after`, oldest first: what OS Pilgrim's overlay showed while it worked, with the run's attached details redacted. Poll while the run is active and pass the returned `after` back. A run Hallpass has not acknowledged has no lines.","responses":{"200":{"description":"The run's lines after `after`.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["activity"],"properties":{"activity":{"$ref":"#/components/schemas/HallPassRunActivity"}}}}},"example":{"success":true,"data":{"activity":{"lines":[{"sequence":41,"code":"visible_browser_start","summary":"I’m finding the browser window and bringing it into view.","at":"2026-10-19T02:23:18Z"},{"sequence":42,"code":"action_verified","summary":"Action 2 verified by fresh application state","at":"2026-10-19T02:23:35Z"}],"after":42}}}}}},"400":{"description":"`after` is not a sequence of zero or more.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"after must be a sequence of zero or more.","data":null}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}},"404":{"description":"No run has this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Run not found.","data":null}}}},"503":{"description":"Hallpass could not be read just now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"The answer could not be sent. Try again.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Read a staff run's activity","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/hallpass/runs/$RUN_ID/activity?after=0\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"after","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"Return lines after this sequence."}]}},"/api/hallpass/runs/{runId}/screen":{"get":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Watch a staff run's browser","description":"Streams a live, masked view of the browser OS Pilgrim drives for the run, passed through unchanged from Pilgrim by Hallpass. The body is `multipart/x-mixed-replace; boundary=pilgrim-screen`. Each part has its own `Content-Type` and `Content-Length`: an `image/jpeg` frame with `X-Frame-Width`, `X-Frame-Height` and `X-Frame-Captured-At` (Unix seconds) headers, or an `application/json` state `{\"state\": \"waiting\" | \"live\" | \"private\" | \"ended\", \"at\": <Unix seconds>}`. A state part comes first, on every change and every 5 seconds. On `private` the client clears the last frame, since frames are withheld while a private step is under way. Pilgrim ends the stream after `ended`, at the latest after 30 minutes; a stream can also close without `ended`, as when the API restarts. While the run is active, reconnect after 3 seconds. Pilgrim masks private input regions in every frame and withholds a frame it cannot mask.","responses":{"200":{"description":"The live view, until Pilgrim ends it or the client disconnects. Disconnecting stops the stream at Hallpass and Pilgrim too.","headers":{"Cache-Control":{"schema":{"type":"string"}},"X-Accel-Buffering":{"schema":{"const":"no"}}},"content":{"multipart/x-mixed-replace":{"schema":{"type":"string","format":"binary"}}}},"403":{"description":"The caller is not a signed-in staff or ADMIN account acting as itself.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for signed-in staff.","data":null}}}},"404":{"description":"No run has this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Run not found.","data":null}}}},"409":{"description":"Nothing to watch now: Hallpass has not acknowledged the run, the run is not active or not in Automatic mode, or its Pilgrim task has not started. Retry after 3 seconds while the run is active.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"This run has nothing to watch right now.","data":null}}}},"429":{"description":"Too many people are watching this run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Too many people are watching this run. Try again shortly.","data":null}}}},"503":{"description":"Hallpass or Pilgrim could not be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"The live view could not be opened just now.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Watch a staff run's browser","code":"curl -N \"https://apis.schoolsoutapp.com/api/hallpass/runs/$RUN_ID/screen\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\" \\\n  --output run-screen.multipart"}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/hallpass/runs/{runId}/trace":{"get":{"tags":["Internal Hallpass runs"],"x-internal":true,"summary":"Read a staff run's trace","description":"Returns up to 1,000 events about the run, oldest first, read from Axiom: OS Pilgrim's telemetry about the run's Pilgrim task (run-log lines, actions and their outcomes, helper operations with their phase timings, model calls, decisions and live-view states, each already redacted by Pilgrim), and Hallpass's and the API's own rows about the run (`kind` `hallpass`: creation, task submission, holds, decisions and answers, cancellations, stops that need a person, the ending), which carry ids, codes, states and amounts only. Pass the returned `after` back to read what followed; events at exactly that time are sent again, so clients de-duplicate on `id`. `complete` is false when a page was full. A 409 means tracing is not set up in this deployment. Until Hallpass names the Pilgrim task the page holds the run's own rows alone and `taskId` is absent; keep reading while the run is active.","responses":{"200":{"description":"The run's events after `after`.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["trace"],"properties":{"trace":{"$ref":"#/components/schemas/HallPassRunTrace"}}}}},"example":{"success":true,"data":{"trace":{"taskId":"13ea19eb-43f6-518e-bd68-61aee5a24bdb","source":"axiom","after":"2026-10-19T08:34:10Z","complete":true,"events":[{"id":"8a7f8702:412","at":"2026-10-19T08:33:36.26Z","launch":"8a7f8702","sequence":412,"kind":"action","name":"dispatching","code":"action_dispatching","step":5,"operation":"private_browser"},{"id":"8a7f8702:415","at":"2026-10-19T08:33:37.091Z","launch":"8a7f8702","sequence":415,"kind":"helper","name":"operatePrivateBrowser","outcome":"failed","code":"browser_search_not_focused","seconds":0.83,"phases":{"findingWindow":0.044,"readingControls":0.677,"starting":0.038},"attempt":1,"turn":"turn-3","counts":{"clicks":3,"refusedClicks":1}},{"id":"8a7f8702:431","at":"2026-10-19T08:33:59.517Z","launch":"8a7f8702","sequence":431,"kind":"helper","name":"clickBrowserControl","outcome":"failed","code":"pointer_target_unavailable","seconds":0.208,"value":"role=AXStaticText subrole=- actions=AXPress,AXScrollToVisible,AXShowMenu ancestors=AXList>AXComboBox>AXGroup>AXGroup listed=no"},{"id":"hallpass:0f3e2a1c-7d6b-4e5f-8a9b-1c2d3e4f5a6b:1792405450000000000","at":"2026-10-19T08:34:10Z","kind":"hallpass","name":"decision_answered","outcome":"accept","code":"confirm_total","value":"decision=4c1d8e2f-9a7b-5c3d-8e6f-2a1b3c4d5e6f option=confirm","runId":"0f3e2a1c-7d6b-4e5f-8a9b-1c2d3e4f5a6b","decidedBy":"person","sender":"apis"}]}}}}}},"400":{"description":"`after` is not an RFC 3339 time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"after must be an RFC 3339 time, or empty.","data":null}}}},"403":{"description":"The caller is not a staff or ADMIN account acting as itself, signed in or with its own key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Staff runs are for staff, signed in or with their own API key.","data":null}}}},"404":{"description":"No run has this ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"Run not found.","data":null}}}},"409":{"description":"Tracing is not set up in this deployment, or the run has no Pilgrim task yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"This run has nothing to trace yet.","data":null}}}},"503":{"description":"Hallpass or Axiom could not be read just now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HallPassRunError"},"example":{"error":true,"message":"The trace could not be read just now.","data":null}}}}},"security":[{"ApiKeyAuth":[]}],"x-auth":"Current staff or ADMIN account acting as itself: the Intelligence session cookie, its account credential, or a named machine key owned by that staff account. The key may start, plan, read, follow, watch and cancel runs; only the signed-in account may answer decisions. Previews, bare service credentials and delegated service requests are rejected. Cookie mutations require a trusted origin and session-bound CSRF token. Registered only when HALLPASS_URL and HALLPASS_SERVICE_TOKEN are set; otherwise 404.","x-curl-examples":[{"title":"Read a staff run's trace","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/hallpass/runs/$RUN_ID/trace?after=\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"after","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Return events at or after this time, the `after` of the previous page. Empty for the first page."}]}},"/api/ingestion/crawler-campaigns/{id}/urls/{url_id}":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"Read saved URL classification details","description":"Read one saved URL belonging to the current campaign generation in data.url, including confidence_threshold from the same snapshot as its projected verdict, full source analysis, named organizations, offerings, rejection reasons, evidence and model provenance. Never acquires pages or calls models.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope."},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."},"404":{"description":"Campaign or saved URL not found."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}},{"name":"url_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}}],"x-curl-examples":[{"title":"Read saved URL classification details","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/1/urls/1\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}},"/api/ingestion/crawler-campaigns/{id}/performance":{"get":{"tags":["Internal crawler monitoring"],"x-internal":true,"summary":"Read mass-crawl worker performance","description":"Read data.performance.workers: bounded latest profiles for shared mass-crawl workers. Each worker has worker_id, observed_at, stale and profile. Profile contains started_at, observed_at, running, stages (stage, count, error_count, total_ms, max_ms, active, oldest_active_ms), slots (search, crawl, classify), and optional resources (cpu_cores, memory_bytes, tasks). Timings are elapsed time, not CPU time. Worker stages may include other campaigns. This operator-only read never starts work.","x-auth":"Current staff or ADMIN operator; standard CSRF for cookie mutations.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Saved campaign state in the standard success/data envelope.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"const":true},"data":{"type":"object","required":["performance"],"properties":{"performance":{"$ref":"#/components/schemas/CrawlerCampaignPerformance"}},"additionalProperties":false}},"additionalProperties":false}}}},"400":{"description":"Invalid input."},"403":{"description":"Staff or ADMIN required."},"409":{"description":"Conflicting generation or idempotency identity."},"404":{"description":"Campaign or saved URL not found."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[1-9][0-9]*$"}}],"x-curl-examples":[{"title":"Read mass-crawl worker performance","code":"curl -X GET \"https://apis.schoolsoutapp.com/api/ingestion/crawler-campaigns/1/performance\" \\\n  -H \"x-api-key: $SCHOOLS_OUT_ACCOUNT_CREDENTIAL\""}]}}},"security":[{"ApiKeyAuth":[]}],"servers":[{"description":"Production","url":"https://apis.schoolsoutapp.com"}],"tags":[{"name":"Data and insights","description":"Discover, filter, search, and read datasets through the supported public contract."},{"name":"Organization catalog","description":"Query the canonical organization catalog and its School’s Out scores."},{"name":"System","description":"Check whether the API is up."},{"name":"Internal canonical queries","description":"Schools Out account/Ask product contract. Machine keys are not accepted."},{"name":"Internal staff geocoding","description":"Staff/ADMIN operations for coverage and confirmed paid backfills. Not an external integration contract."},{"name":"Internal family profiles","description":"Private child profiles shared only with explicitly invited and accepted guardians. Machine keys and service impersonation are rejected."},{"name":"Internal family bookings","description":"Parent-approved camp bookings: the saved card, approval with a spending limit, status polling, camp questions and cancellation. Registered only with BOOKINGS_ENABLED=true; machine keys and service impersonation are rejected."},{"name":"Internal Explorer map","description":"Read-only geographic browsing for Intelligence. Catalog access and preview disclosure are enforced before spatial grouping."},{"name":"Internal Overseer","description":"Staff/ADMIN singleton directive and audit monitoring."},{"name":"Internal sign-in handoff","description":"Auth-website handoff into a registered School’s Out product: Intelligence or the mobile app. Not an external integration contract."},{"name":"Internal Gmail","description":"Private parent Gmail consent and connection status."},{"name":"Internal Hallpass runs","description":"Staff/ADMIN Hallpass tasks of any kind outside a family booking: rehearse a checkout or evaluate Hallpass, then follow, answer and cancel it. Runs place the order by default, up to HALLPASS_STAFF_MAX_SPEND_CENTS; a rehearsal stops at the checkout total. Registered only when HALLPASS_URL is configured. Staff authenticate with their signed-in session or account credential, or with a named machine key they own, which may start, read, follow and cancel runs; answering a decision needs the signed-in person."}]}