{"openapi":"3.1.0","info":{"title":"Jev Screen API","version":"0.2.0","description":"Screening judgment as an API. Send a CV and a role profile; get scored dimensions, a composite, a confidence value, and a tier (shortlist / review / weak). Stateless, redacted by default, never returns a reject. Custom account roles via role: 'own:<id>'. Also speaks MCP at POST /mcp for AI agents. Header conveniences: X-Request-Id, X-Sandbox, Idempotency-Key.","contact":{"email":"hi@arsana.cloud"}},"servers":[{"url":"https://api.jev.arsana.cloud"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"}},"schemas":{"RoleSummary":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"dimensions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"type":{"type":"string","enum":["noul","score","choice"]},"instructions":{"type":"string"}}}},"weights":{"type":"object","additionalProperties":{"type":"number"}},"policy":{"type":"object","additionalProperties":true}}},"ScreenResult":{"type":"object","properties":{"role":{"type":"string"},"engine":{"type":"integer","examples":[2]},"model":{"type":"string","examples":["jev-1.13.0"]},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"}}},"redacted":{"type":"boolean"},"dimensions":{"type":"object","additionalProperties":{"oneOf":[{"type":"object","properties":{"type":{"const":"score"},"score":{"type":"number"},"normalized":{"type":"number","minimum":0,"maximum":1},"confidence":{"type":"number"}}},{"type":"object","properties":{"type":{"const":"noul"},"probability":{"type":"number","minimum":0,"maximum":1},"uncertain":{"type":"boolean","description":"yes/no parity: the model could not tell"}}},{"type":"object","properties":{"type":{"const":"choice"},"choice":{"type":"string"},"probabilities":{"type":"object","additionalProperties":{"type":"number"}}}}]}},"composite":{"type":"number","nullable":true},"confidence":{"type":"number"},"tier":{"type":"string","enum":["shortlist","review","weak"]},"tier_reason":{"type":"string"},"flags":{"type":"object","description":"Present only when something needs human attention","properties":{"red_flags":{"type":"array","items":{"type":"string"}},"uncertain_nouls":{"type":"array","items":{"type":"string"}}}},"request_id":{"type":"string"}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"request_id":{"type":"string"}},"required":["error"]}}},"paths":{"/health":{"get":{"summary":"Liveness probe","security":[],"responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/openapi.json":{"get":{"summary":"This document","security":[],"responses":{"200":{"description":"OpenAPI 3.1 spec"}}}},"/v1/roles":{"get":{"summary":"List role profiles","responses":{"200":{"description":"Available role profiles with dimensions and weights","content":{"application/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}}}}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/roles/{id}":{"get":{"summary":"Get one role profile (full rubric)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Role profile with full rubric levels","content":{"application/json":{"schema":{"type":"object","properties":{"role":{"$ref":"#/components/schemas/RoleSummary"}}}}}},"404":{"description":"Unknown role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screen":{"post":{"summary":"Screen one applicant","description":"Judges one CV against a role profile. Tier policy is arithmetic in the service: low confidence always routes to review, flagged red flags force review, and the API never returns a reject.","parameters":[{"name":"X-Sandbox","in":"header","schema":{"type":"boolean"},"description":"true = deterministic sample response, no quota"},{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"description":"Replay protection for retries (24h)"},{"name":"X-Request-Id","in":"header","schema":{"type":"string"},"description":"Echoed in header and body"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["applicant"],"properties":{"role":{"type":"string","examples":["ai-community-admin","own:r_abc123"],"description":"Role profile id, your own role as own:<id>, or omit and pass inline 'profile'"},"profile":{"type":"object","additionalProperties":true,"description":"Inline role profile"},"applicant":{"type":"object","required":["cv_text"],"properties":{"cv_text":{"type":"string","minLength":200,"description":"Plain-text CV (Bahasa Indonesia or English)"},"form_answers":{"type":"object","additionalProperties":true}}},"redact":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Screening result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenResult"}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"cv_text under the extraction floor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Burst limit (see Retry-After) or monthly quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Judgment model unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screen/batch":{"post":{"summary":"Screen up to 25 applicants in one request","description":"Same judgment as /v1/screen, run in parallel. Each item returns a full result or an in-band error; one bad CV never fails the batch. Each applicant counts as one screen against quota.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["applicants"],"properties":{"role":{"type":"string"},"profile":{"type":"object","additionalProperties":true},"applicants":{"type":"array","minItems":1,"maxItems":25,"items":{"type":"object","required":["cv_text"],"properties":{"cv_text":{"type":"string"},"form_answers":{"type":"object","additionalProperties":true}}}},"redact":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Per-applicant results; index-aligned with the request","content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string"},"count":{"type":"integer"},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"}}},"results":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/ScreenResult"},{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}]}},"request_id":{"type":"string"}}}}}},"401":{"description":"Invalid API key"},"429":{"description":"Burst limit or monthly quota"}}}},"/v1/eval":{"post":{"summary":"Calibration report: compare API tiers with your human decisions","description":"Send the decision pairs you collected (API tier vs what your humans decided) and get a disagreement analysis: confusion matrix, false-weak rate, false-shortlist rate, automation-readiness verdict. Stateless — nothing is stored.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["decisions"],"properties":{"decisions":{"type":"array","minItems":1,"maxItems":5000,"items":{"type":"object","required":["tier","human"],"properties":{"tier":{"type":"string","enum":["shortlist","review","weak"]},"human":{"type":"string","enum":["advance","review","reject"]}}}}}}}}},"responses":{"200":{"description":"Disagreement report"}}}},"/mcp":{"post":{"summary":"MCP endpoint for AI agents (JSON-RPC 2.0)","description":"Streamable-HTTP MCP server. Agents connect with the same X-API-Key header. Tools: screen_candidate, list_roles, get_role.","security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"JSON-RPC 2.0 request object"}}}},"responses":{"200":{"description":"JSON-RPC response"}}}}}}