{"openapi":"3.1.0","info":{"title":"EstHost Enterprise Data Scrubber API","description":"\n## Private processing. Enterprise integration.\n\n**EstHost** removes configured personal identifiers from text before it enters\nanalytics, support, or AI workflows. Send `{\"text\": \"string\"}` to\n`POST /api/v1/scrub` and receive scrubbed text, remaining request quota, and\ntransparent engine telemetry.\n\n### Zero-Cloud · RAM-only text processing\n\nScrubbing runs locally on this bare-metal server. Submitted text is processed in\napplication memory; the scrub endpoint does not write payloads or scrubbed output\nto SQLite or send them to an external AI service. Account records, redaction\nsettings, API keys, and usage counters are stored separately in SQLite.\n\n### Worldwide AI (SpaCy) + Native Baltic NLP Lexicon\n\nName redaction combines a local **spaCy** named-entity model with a **Native Baltic\nNLP Lexicon**, currently covering Estonian names and supported suffixes. This\ndeployment uses the English `en_core_web_sm` model; recognition varies by language\nand input. If the AI model is unavailable, the native lexicon remains available.\nEmail, IP address, phone, and custom-keyword rules follow the account's dashboard\nsettings. Name detection runs only when name redaction is enabled.\n\n### GDPR compliance support\n\nLocal processing and data minimization support GDPR compliance workflows.\nRedaction is configurable and best effort: review results for your use case;\nautomated scrubbing alone does not establish anonymization or legal compliance.\nSee the [privacy notice](/privacy) and [service terms](/terms).\n\n### Authenticate and integrate\n\n1. Obtain your API key from the [dashboard](/dashboard).\n2. Select **Authorize** and enter the key; Swagger sends it as `X-API-Key`.\n3. Submit JSON with a required `text` string. Review `scrubbed_text`,\n   `requests_remaining`, and `debug` in the response.\n\nEach successful call consumes one request from the account quota. Missing or\ninvalid keys return **403**; an exhausted quota returns **429**.\n","termsOfService":"/terms","version":"v2.4.0"},"paths":{"/":{"get":{"summary":"Index","operationId":"index__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/terms":{"get":{"summary":"Terms","operationId":"terms_terms_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/privacy":{"get":{"summary":"Privacy","operationId":"privacy_privacy_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/register":{"get":{"summary":"Register Page","operationId":"register_page_register_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Register","operationId":"register_register_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_register_register_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/login":{"get":{"summary":"Login Page","operationId":"login_page_login_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Login","operationId":"login_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/logout":{"get":{"summary":"Logout","operationId":"logout_logout_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/dashboard":{"get":{"summary":"Dashboard","operationId":"dashboard_dashboard_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/dashboard/settings":{"post":{"summary":"Update Settings","operationId":"update_settings_dashboard_settings_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/checkout":{"get":{"summary":"Checkout","operationId":"checkout_checkout_get","parameters":[{"name":"plan","in":"query","required":true,"schema":{"type":"string","title":"Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/scrub":{"post":{"tags":["Data scrubbing"],"summary":"Scrub sensitive identifiers from text","description":"Scrub text locally using the authenticated account's redaction settings.\n\n### Request\nSend `Content-Type: application/json` and the required `X-API-Key` header.\nThe body must be an object containing a required string: `{\"text\": \"string\"}`.\nFor example: `{\"text\": \"Contact hello@example.com\"}`. In this reference,\nuse **Authorize** to enter your key before selecting **Try it out**.\n\n### Processing\nDashboard settings determine whether names, email addresses, IPv4/IPv6\naddresses, phone numbers, and custom keywords are redacted. Name redaction\ncombines the local spaCy model (when available) with the native Estonian\nlexicon. Input and output text are processed in RAM and are not stored by\nthis endpoint. Account settings and usage counters remain in SQLite.\n\n### Response and telemetry\nThe JSON response contains `status`, `scrubbed_text`, `requests_remaining`,\nand `debug`. The debug object reports `nlp_engine` availability and the\nconfigured `coverage` label. These fields describe the engine, not detection\nconfidence or a guarantee that every identifier was removed.\nEvery successful request increments the account's usage counter once.\n\n### Errors\n- **403**: `Missing X-API-Key` or `Invalid Key`.\n- **429**: `Quota exceeded`.\n- **422**: the JSON body is missing or fails request validation.","operationId":"scrub_data_api_v1_scrub_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RawData"}}},"required":true},"responses":{"200":{"description":"Text processed using the account's dashboard settings. One request has been charged to the quota.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScrubResponse"},"example":{"status":"success","requests_remaining":999,"scrubbed_text":"Contact [REDACTED_EMAIL]","debug":{"nlp_engine":"Online","coverage":"Worldwide AI + Native Estonian Hybrid"}}}}},"403":{"description":"X-API-Key is missing, empty, or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScrubError"},"examples":{"missing_key":{"summary":"Missing or empty API key","value":{"detail":"Missing X-API-Key"}},"invalid_key":{"summary":"Unrecognized API key","value":{"detail":"Invalid Key"}}}}}},"429":{"description":"The account's request quota is exhausted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScrubError"},"example":{"detail":"Quota exceeded"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"EstHostApiKey":[]}]}}},"components":{"schemas":{"Body_login_login_post":{"properties":{"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"}},"type":"object","required":["username","password"],"title":"Body_login_login_post"},"Body_register_register_post":{"properties":{"username":{"type":"string","title":"Username"},"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"},"tos_agree":{"type":"string","title":"Tos Agree"}},"type":"object","required":["username","email","password"],"title":"Body_register_register_post"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"RawData":{"properties":{"text":{"type":"string","title":"Text","description":"Required input text to scrub. Send a JSON object such as {\"text\": \"string\"}. Redaction follows the API key owner's dashboard settings; no extra configuration fields are needed.","examples":["string"]}},"type":"object","required":["text"],"title":"RawData","description":"JSON request body for account-configured text scrubbing."},"ScrubDebug":{"properties":{"nlp_engine":{"type":"string","title":"Nlp Engine","description":"Local spaCy model status: Online when loaded, or Offline followed by the loader error. Availability does not mean name redaction is enabled for the account.","examples":["Online"]},"coverage":{"type":"string","title":"Coverage","description":"Configured engine/lexicon label. Current native lexicon coverage is Estonian; this label is not a guarantee of recognition in every language.","examples":["Worldwide AI + Native Estonian Hybrid"]}},"type":"object","required":["nlp_engine","coverage"],"title":"ScrubDebug","description":"Engine telemetry; this object does not contain the original input text."},"ScrubError":{"properties":{"detail":{"type":"string","title":"Detail","description":"Reason the request was rejected.","examples":["Missing X-API-Key"]}},"type":"object","required":["detail"],"title":"ScrubError","description":"Existing authentication and quota error response."},"ScrubResponse":{"properties":{"status":{"type":"string","const":"success","title":"Status","description":"Successful completion of the scrub request."},"requests_remaining":{"type":"integer","title":"Requests Remaining","description":"Account quota remaining after this successful request consumes one request.","examples":[999]},"scrubbed_text":{"type":"string","title":"Scrubbed Text","description":"Input text with identifiers replaced according to the account's enabled redaction settings. Text may be unchanged when no configured rule matches.","examples":["Contact [REDACTED_EMAIL]"]},"debug":{"$ref":"#/components/schemas/ScrubDebug","description":"NLP engine availability and configured detection coverage."}},"type":"object","required":["status","requests_remaining","scrubbed_text","debug"],"title":"ScrubResponse","description":"Document the existing successful response without changing serialization."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"EstHostApiKey":{"type":"apiKey","description":"Required for POST /api/v1/scrub. Enter the API key from your EstHost dashboard without a prefix.","in":"header","name":"X-API-Key"}}},"tags":[{"name":"Data scrubbing","description":"Authenticated, account-configured text redaction with quota and engine telemetry."}]}