{"openapi":"3.1.0","info":{"title":"Loker Dollar HITL Screening API","version":"1.0.0","description":"Submit a candidate against a job spec, get an AI score, and get a human-reviewed result delivered to your webhook. Every submission is scored by AI and then approved, rejected, or edited by a human reviewer before delivery — never auto-delivered from the model. Every state transition is recorded in an append-only audit ledger, exportable per tenant.","contact":{"name":"Loker Dollar","url":"https://lokerdollar.com/en/developers/screening-api"}},"servers":[{"url":"https://lokerdollar.com"}],"security":[{"bearerAuth":[]}],"paths":{"/api/screening/v1/screen":{"post":{"operationId":"submitCandidate","summary":"Submit a candidate for screening","description":"Accepts a candidate against a job spec, charges one screening credit, and queues it for AI scoring followed by mandatory human review. A replayed `idempotencyKey` for the same tenant returns the original request unchanged — no second charge, no duplicate.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["idempotencyKey","candidate","jobSpec"],"properties":{"idempotencyKey":{"type":"string","description":"Unique per tenant. Replaying the same key returns the existing request instead of creating a new one."},"candidate":{"$ref":"#/components/schemas/CandidateBlob"},"jobSpec":{"$ref":"#/components/schemas/JobSpecV1"}}},"example":{"idempotencyKey":"req-backend-eng-jane-2026-08-03","candidate":{"kind":"structured","fullName":"Jane Doe","email":"jane.doe@example.com","summary":"5 years backend engineering focused on Node.js and PostgreSQL; led a 4-person team at a Series A logistics startup.","skills":["Node.js","PostgreSQL","TypeScript","AWS"],"experienceYears":5},"jobSpec":{"title":"Senior Backend Engineer","mustHaves":["Node.js","PostgreSQL","3+ years backend experience"],"niceToHaves":["AWS","Prior team-lead experience"],"salaryBandMinIdr":25000000,"salaryBandMaxIdr":40000000,"description":"Own the payments service for a Series B fintech."}}}}},"responses":{"200":{"description":"Idempotent replay — same body already accepted; returns the existing request's current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenAcceptedResult"}}}},"201":{"description":"Accepted — queued for scoring.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenAcceptedResult"},"example":{"requestId":"scr_7c1e0a9b4f2d4c8e","state":"received"}}}},"400":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Free-tier screen cap or paid-tier credit wallet exhausted. `error.upsell.upgradeUrl` always carries a next step — never a silent degrade.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequiredError"}}}},"403":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/screening/v1/usage":{"get":{"operationId":"getScreeningUsage","summary":"Read the caller's screening credit wallet","description":"Check remaining credits before submitting, instead of discovering a cap via a failed submit.","responses":{"200":{"description":"The caller's current usage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreeningUsage"},"example":{"tenantId":"biz_9f3a2c","planTier":"free","creditsRemaining":37,"creditsCap":50,"usagePercent":0.26,"nearLimit":false,"resetAt":"2026-09-01T00:00:00.000Z","freeScreenCap":50}}}},"401":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/screening/v1/audit":{"get":{"operationId":"exportScreeningAudit","summary":"Export the append-only audit ledger","description":"Paginated, tenant-scoped export of every state transition — this ledger is the compliance record: intake, scoring, the human review decision, and delivery, each as its own row. A caller can only ever read its own tenant's rows.","parameters":[{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only seeds the first page; a `cursor` takes precedence once supplied."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque keyset cursor from a prior page's `nextCursor`."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"A page of audit events.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditPage"}}}},"400":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Error envelope with a machine-readable `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Employer API key as a bearer token, e.g. `Authorization: Bearer lk_live_…`."}},"schemas":{"CandidateBlob":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"resume_ref"},"resumeRef":{"type":"string"},"filename":{"type":"string"}},"required":["kind","resumeRef"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"structured"},"fullName":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"summary":{"type":"string"},"skills":{"readOnly":true,"type":"array","items":{"type":"string"}},"experienceYears":{"type":"number"}},"required":["kind","fullName"],"additionalProperties":false}]},"JobSpecV1":{"type":"object","properties":{"title":{"type":"string"},"mustHaves":{"readOnly":true,"type":"array","items":{"type":"string"}},"niceToHaves":{"readOnly":true,"type":"array","items":{"type":"string"}},"salaryBandMinIdr":{"type":"number"},"salaryBandMaxIdr":{"type":"number"},"description":{"type":"string"}},"required":["title","mustHaves"],"additionalProperties":false},"ScoreResultV1":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"schemaVersion":{"type":"number","const":1},"score":{"type":"number"},"dimensions":{"readOnly":true,"minItems":1,"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"score":{"type":"number"},"evidence":{"type":"string"}},"required":["name","score","evidence"],"additionalProperties":false}},"rationale":{"type":"string","minLength":1},"confidence":{"type":"number"},"modelId":{"type":"string"},"promptVersion":{"type":"string"}},"required":["schemaVersion","score","dimensions","rationale","confidence","modelId","promptVersion"],"additionalProperties":false,"example":{"schemaVersion":1,"score":78,"dimensions":[{"name":"must-haves","score":85,"evidence":"5 years backend engineering focused on Node.js and PostgreSQL"},{"name":"seniority fit","score":70,"evidence":"led a 4-person team at a Series A logistics startup"}],"rationale":"Meets every must-have and has one prior lead role; salary expectations were not provided so band fit is unconfirmed.","confidence":0.82,"modelId":"@cf/google/gemma-4-26b-a4b-it","promptVersion":"screening-scorer-v1"}},"ScreenAcceptedResult":{"type":"object","required":["requestId","state"],"properties":{"requestId":{"type":"string","example":"scr_7c1e0a9b4f2d4c8e"},"state":{"type":"string","enum":["received","parsed","scored","pending_review","approved","rejected","edited","delivered","failed","expired"]}}},"ScreeningUsage":{"type":"object","required":["tenantId","planTier","creditsRemaining","creditsCap","usagePercent","nearLimit","resetAt"],"properties":{"tenantId":{"type":"string"},"planTier":{"type":"string","enum":["free","starter","pro","scale"]},"creditsRemaining":{"type":"integer"},"creditsCap":{"type":"integer"},"usagePercent":{"type":"number","minimum":0,"maximum":1},"nearLimit":{"type":"boolean","description":"True at 80%+ of `creditsCap` used."},"resetAt":{"type":["string","null"],"format":"date-time"},"freeScreenCap":{"type":"integer","description":"Present only for `planTier: \"free\"`."}}},"AuditPage":{"type":"object","required":["events","nextCursor"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/AuditEvent"}},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page; null on the last page."}}},"AuditEvent":{"type":"object","required":["id","requestId","toState","actor","createdAt"],"properties":{"id":{"type":"string"},"requestId":{"type":"string"},"fromState":{"type":["string","null"]},"toState":{"type":"string"},"actor":{"type":"string","description":"`system` or `reviewer:<id>`."},"payload":{},"createdAt":{"type":"string","format":"date-time"}}},"ScreeningWebhookDelivery":{"type":"object","description":"Body posted to your `webhookUrl` after a score or a review decision — you receive this, you never call an endpoint for it. Verify `X-Screening-Signature: sha256=<hex>` (HMAC-SHA256 over the raw body, your `webhookSecret`) before trusting the payload.","required":["requestId","tenantId","event","result","deliveredAt"],"properties":{"requestId":{"type":"string"},"tenantId":{"type":"string"},"event":{"type":"string","enum":["screening.scored","screening.review_decided"]},"result":{"description":"A `ScoreResultV1` for `screening.scored`, a `ReviewDecisionV1` for `screening.review_decided`."},"deliveredAt":{"type":"string","format":"date-time"}},"example":{"requestId":"scr_7c1e0a9b4f2d4c8e","tenantId":"biz_9f3a2c","event":"screening.review_decided","result":{"schemaVersion":1,"decision":"approved","reviewerId":"reviewer_412","reviewerRole":"recruiter","latencyMs":46000,"note":"Strong must-have coverage, forward to the hiring manager."},"deliveredAt":"2026-08-03T09:14:22.000Z"}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","forbidden","rate_limited","payment_required","not_found","invalid_request","service_disabled","internal"]},"message":{"type":"string"}}}}},"PaymentRequiredError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","upsell"],"properties":{"code":{"type":"string","enum":["payment_required"]},"message":{"type":"string"},"upsell":{"type":"object","required":["upgradeUrl"],"properties":{"upgradeUrl":{"type":"string","format":"uri"},"freeScreenCap":{"type":"integer"}}}}}}}}}}