Developer documentation · Draft v1
Application quality.
Built into your workflow.
Send a resume, a job, and your screening questions. Receive structured findings with source evidence, ready for review queues and reporting.
This is the implementation specification for our future public API. The examples are illustrative, valid JSON based on the playground’s evaluation format—not live analysis. The hostname, authentication, and versioned endpoint below are placeholders.
01 / Overview
One application. One structured result.
The first API version will evaluate one resume against one job per request and return the completed result synchronously. It will not create a stored candidate profile or require polling.
/v1/evaluationsProposedUse the result to surface applications for human review, record criterion-level findings in your own system, or aggregate quality by job and recruitment source. Keep your application and source IDs in your system and join the response there; this endpoint does not perform attribution or ad-spend reporting.
Implemented today: the local playground uses POST /api/evaluate. The public route and API-key authentication described here are not implemented. Do not expose the local route as a public API.
02 / Authentication
Connect from your server.
The proposed API requires HTTPS and a Signal API key in the Authorization header. Keep the key on your server; never place it in browser code or a public repository. Key issuance will be available when the API launches.
Authorization: Bearer $SIGNAL_API_KEY
Content-Type: application/json
Accept: application/jsonDownload the request JSON below as evaluation-request.json. This command shows the intended integration; api.signal.example is a reserved example domain and will not process requests.
curl --request POST 'https://api.signal.example/v1/evaluations' \
--header "Authorization: Bearer $SIGNAL_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--max-time 45 \
--data-binary @evaluation-request.json03 / Request
Bring the job into the assessment.
Send extracted plain text, not a PDF, DOCX, URL, or base64 file. All fields below are required, with empty values allowed only where specified. The example is a fictional reporting analyst, with a supported negative answer and a separate unanswered availability question.
| Field | Contract |
|---|---|
resume | Nonempty string; at most 20,000 characters. Extract and redact identifying details before sending where possible. |
fictional | Boolean. Use true for synthetic examples and false for real applications. Fictional context does not automatically lower job fit. |
job.title / description | Nonempty strings; title ≤160 characters, description ≤8,000. |
job.seniority / location | Strings; seniority ≤100 characters, location ≤160. Use an empty string when unspecified. |
job.arrangement | One of onsite, hybrid, remote. Describe geographical and attendance constraints explicitly in the job description. |
job.requirements | Array of 0–10 objects: id (1–80 characters), text (1–400), priority (required or preferred). Use stable, unique req_ IDs. |
questions | Array of 0–10 objects: id (1–80 characters), text (1–400), type (yes_no, choice, excerpt), options (array). Use stable, unique q_ IDs. |
questions[].options | For choice: 2–20 distinct, nonempty strings, each ≤200 characters. For yes_no and excerpt: []. An unknown outcome is added automatically; do not add it as a choice. |
IDs must be unique across requirements and questions. The req_ and q_ prefixes avoid collisions with internal assessment names; do not end IDs with _evidence. Text limits count JavaScript string length (UTF-16 code units); whitespace is trimmed.
{
"resume": "PROFILE\nReporting analyst with experience building dashboards for operations teams.\nEXPERIENCE\nReporting Analyst, 2022-present. I use SQL to query operational data and Excel to prepare weekly reports.\nI independently maintain dashboards, investigate data quality issues, and present findings to team leads.\nWORK PREFERENCE\nI work remotely from the United Kingdom.\nTOOLS\nSQL is my primary reporting tool. I have not used Tableau professionally.",
"fictional": true,
"job": {
"title": "Reporting Analyst",
"description": "Build operational dashboards, investigate data quality, and explain results to team leads. SQL is required; Excel is preferred. This mid-level role is remote within the United Kingdom.",
"seniority": "Mid-level",
"location": "United Kingdom",
"arrangement": "remote",
"requirements": [
{
"id": "req_sql",
"text": "Experience using SQL for reporting",
"priority": "required"
},
{
"id": "req_excel",
"text": "Experience preparing reports in Excel",
"priority": "preferred"
}
]
},
"questions": [
{
"id": "q_tableau",
"text": "Have you used Tableau professionally?",
"type": "yes_no",
"options": []
},
{
"id": "q_tool",
"text": "What is your primary reporting tool?",
"type": "choice",
"options": [
"SQL",
"Excel",
"Tableau"
]
},
{
"id": "q_work",
"text": "Describe your dashboard responsibilities.",
"type": "excerpt",
"options": []
},
{
"id": "q_start",
"text": "Are you available to start next Monday?",
"type": "yes_no",
"options": []
}
]
}The complete UTF-8 JSON body is limited to 120,000 bytes. Expanded analysis requests also have a processing budget, so combinations of long inputs may be rejected even within individual field limits. Content must never be silently truncated. Shorten the resume, job, criteria, or questions after a budget error.
04 / Response
Findings you can inspect.
A successful request returns 200 OK, Content-Type: application/json, and Cache-Control: no-store. This is a complete illustrative response to the example request. Scores and timing are examples, not measured accuracy or a latency promise.
{
"fit": {
"label": "suitable",
"explanation": "The resume shows adequate alignment. Review any missing requirements, preferences, or unresolved constraints.",
"review": false
},
"dimensions": {
"relevance": {
"value": "relevant",
"confidence": 0.94,
"probabilities": {
"relevant": 0.97,
"unrelated": 0.01,
"unknown": 0.02
},
"evidence": {
"id": "b1",
"text": "Reporting analyst with experience building dashboards for operations teams."
},
"review": false
},
"skills": {
"value": "strong",
"confidence": 0.94,
"probabilities": {
"strong": 0.92,
"adequate": 0.05,
"weak": 0.01,
"unknown": 0.02
},
"evidence": {
"id": "b3",
"text": "Reporting Analyst, 2022-present. I use SQL to query operational data and Excel to prepare weekly reports."
},
"review": false
},
"experience": {
"value": "adequate",
"confidence": 0.94,
"probabilities": {
"strong": 0.1,
"adequate": 0.84,
"weak": 0.01,
"unknown": 0.05
},
"evidence": {
"id": "b4",
"text": "I independently maintain dashboards, investigate data quality issues, and present findings to team leads."
},
"review": false
},
"seniority": {
"value": "met",
"confidence": 0.94,
"probabilities": {
"met": 0.95,
"not_met": 0.01,
"unknown": 0.04
},
"evidence": {
"id": "b4",
"text": "I independently maintain dashboards, investigate data quality issues, and present findings to team leads."
},
"review": false
},
"location": {
"value": "met",
"confidence": 0.94,
"probabilities": {
"met": 0.95,
"not_met": 0.01,
"unknown": 0.04
},
"evidence": {
"id": "b6",
"text": "I work remotely from the United Kingdom."
},
"review": false
}
},
"requirements": [
{
"id": "req_sql",
"text": "Experience using SQL for reporting",
"priority": "required",
"value": "met",
"confidence": 0.94,
"probabilities": {
"met": 0.95,
"not_met": 0.01,
"unknown": 0.04
},
"evidence": {
"id": "b3",
"text": "Reporting Analyst, 2022-present. I use SQL to query operational data and Excel to prepare weekly reports."
},
"review": false
},
{
"id": "req_excel",
"text": "Experience preparing reports in Excel",
"priority": "preferred",
"value": "met",
"confidence": 0.94,
"probabilities": {
"met": 0.95,
"not_met": 0.01,
"unknown": 0.04
},
"evidence": {
"id": "b3",
"text": "Reporting Analyst, 2022-present. I use SQL to query operational data and Excel to prepare weekly reports."
},
"review": false
}
],
"signals": {
"spam": {
"value": "no_clear_indicators",
"confidence": 0.94,
"probabilities": {
"detected": 0.02,
"no_clear_indicators": 0.96,
"unknown": 0.02
},
"evidence": {
"id": "b1",
"text": "Reporting analyst with experience building dashboards for operations teams."
},
"review": false
},
"authenticity": {
"value": "unknown",
"confidence": 0.94,
"probabilities": {
"fictional": 0.01,
"concerns": 0.02,
"unverified": 0.9,
"unknown": 0.07
},
"evidence": null,
"review": true
},
"ai": {
"value": "unknown",
"confidence": 0.66,
"probabilities": {
"detected": 0.1,
"no_clear_indicators": 0.7,
"unknown": 0.2
},
"evidence": null,
"review": true
}
},
"answers": [
{
"value": "no",
"confidence": 0.94,
"probabilities": {
"yes": 0.01,
"no": 0.97,
"unknown": 0.02
},
"evidence": {
"id": "b8",
"text": "SQL is my primary reporting tool. I have not used Tableau professionally."
},
"review": false,
"id": "q_tableau",
"question": "Have you used Tableau professionally?",
"answer": "No"
},
{
"value": "option_0",
"confidence": 0.94,
"probabilities": {
"option_0": 0.95,
"option_1": 0.02,
"option_2": 0.01,
"unknown": 0.02
},
"evidence": {
"id": "b8",
"text": "SQL is my primary reporting tool. I have not used Tableau professionally."
},
"review": false,
"id": "q_tool",
"question": "What is your primary reporting tool?",
"answer": "SQL"
},
{
"value": "answered",
"confidence": 0.94,
"probabilities": {
"answered": 0.96,
"unknown": 0.04
},
"evidence": {
"id": "b4",
"text": "I independently maintain dashboards, investigate data quality issues, and present findings to team leads."
},
"review": false,
"id": "q_work",
"question": "Describe your dashboard responsibilities.",
"answer": "I independently maintain dashboards, investigate data quality issues, and present findings to team leads."
},
{
"value": "unknown",
"confidence": 0.9,
"probabilities": {
"yes": 0.05,
"no": 0.05,
"unknown": 0.9
},
"evidence": null,
"review": true,
"id": "q_start",
"question": "Are you available to start next Monday?",
"answer": "Not stated / cannot determine"
}
],
"reviewFlags": [],
"elapsedMs": 3130
}| Field | Contract |
|---|---|
fit | Object with label, explanation (templated string), and review (boolean). No overall confidence score is fabricated. |
dimensions | Five Finding objects: relevance, skills, experience, seniority, location. |
requirements | One result per submitted criterion, in input order. Original id, text, priority plus Finding fields. |
signals | Independent Finding objects: spam, authenticity (claims review, not verification), and ai (experimental writing indicators). None determines job fit. |
answers | One result per question, in input order: id, question, answer (string), plus Finding fields. Match using id, not wording. |
reviewFlags | Array of human-readable role/criterion and selected document review notes. May be empty even if a signal or answer needs review; inspect each Finding.review too. Do not parse these strings as stable codes. |
elapsedMs | Nonnegative integer: server evaluation duration in milliseconds, excluding client network time. |
The playground may also return cached for saved fictional demonstrations. It is not part of the proposed public contract; do not depend on it for customer applications. Consumers should tolerate additional response fields.
05 / Reading results
Unknown is an answer, too.
| Field | Contract |
|---|---|
Finding.value | Accepted categorical result, or unknown when evidence or confidence is insufficient. See the allowed values below. |
Finding.confidence | Number from 0 to 1: initial model confidence. Not a match percentage, correctness guarantee, or probability of spam. |
Finding.probabilities | Map from every initial category to a number from 0 to 1. Probabilities sum to approximately 1; they remain unchanged when the final value becomes unknown. |
Finding.evidence | { id, text } for an independently supported finding; otherwise null. text is a verbatim block from the sanitized resume. b0, b1, … IDs are scoped to this evaluation, not stable across edits. Long resumes may have adjacent lines merged into a block. |
Finding.review | Boolean. True means the finding needs review; do not treat it as a supported positive or negative. |
The provisional acceptance floor is 0.7 for the initial finding and its separate evidence check. High initial confidence can still yield unknown with null evidence. The evidence-check confidence is not returned. The floor is tunable, not an accuracy claim.
| Field | Contract |
|---|---|
fit.label | great_fit · suitable · unsuitable · noise · insufficient_evidence |
dimensions.relevance.value | relevant · unrelated · unknown |
skills / experience value | strong · adequate · weak · unknown |
seniority / location / criterion value | met · not_met · unknown |
signals.spam.value | detected · no_clear_indicators · unknown |
signals.authenticity.value | fictional · concerns · unverified · unknown. No value verifies a career history. |
signals.ai.value | detected · no_clear_indicators · unknown. Experimental artifacts only; no result establishes authorship. |
yes_no answer value | yes · no · unknown. answer is Yes, No, or Not stated / cannot determine. No requires explicit negative evidence. |
choice answer value | option_0, option_1, … (zero-based input option index), or unknown. answer contains the selected option text or Not stated / cannot determine. |
excerpt answer value | answered · unknown. answer is the exact evidence.text, or Not stated / cannot determine; no generated narrative. |
- Great fit: strong skills and experience, all required criteria evidenced, and supported seniority/location constraints.
- Suitable: adequate core alignment, with possible missing information or unmet preferences.
- Unsuitable: relevant background but an evidenced required failure, inadequate core capability, or explicit level/work-location conflict.
- Noise: no meaningful relevant or transferable experience. This does not mean spam.
- Insufficient evidence: relevance or core capability cannot be assessed reliably enough to classify.
Missing information is not failure. A different city alone does not prove a location mismatch; exceeding the requested seniority is not a penalty. Protected traits, inferred identity, salary, availability, and authorization must not be guessed. Document signals remain separate from fit. Use findings to support human decisions, not as verified facts or automatic rejection instructions.
06 / Errors & retries
Explicit failures. No invented results.
The following error envelope and statuses are proposed for the public API. The existing local endpoint uses a simpler error string and different status mappings.
{
"error": {
"code": "analysis_budget_exceeded",
"message": "Shorten the supplied text or reduce the number of questions.",
"retryable": false
}
}| Field | Contract |
|---|---|
400 · invalid_request | Malformed JSON, missing fields, invalid types, duplicate/reserved IDs, or field limits exceeded. Correct the request. |
401 · invalid_api_key | Missing or invalid Signal API key. Correct the credentials; do not retry unchanged. |
413 · request_too_large | JSON body exceeds 120,000 bytes. Reduce the payload. |
415 · unsupported_media_type | Content-Type is not application/json. Send plain text inside JSON. |
422 · analysis_budget_exceeded | Valid input cannot fit the analysis budget. Shorten content; retryable is false. |
429 · rate_limited | Capacity or account limit reached. retryable is true; Retry-After specifies a positive number of seconds. Launch quotas are not yet set. |
502 · analysis_failed | The analysis service failed or returned an invalid result. retryable is true; no partial or fabricated success response. |
503 · service_unavailable | Analysis is temporarily unavailable. retryable is true. |
504 · analysis_timeout | The proposed 40-second server deadline expired. retryable is true. |
Errors return Cache-Control: no-store. error.code is the stable machine-readable field; message is safe display text with no submitted content or raw upstream details. retryable is false for 400/401/413/415/422 and true for 429/502/503/504.
For transient failures, use a bounded retry policy with exponential backoff and jitter, and honor Retry-After. A retry is a new evaluation; idempotency and billing for failed/cancelled attempts are not specified yet. Avoid blind POST retries after a connection loss: the server may already have completed work. Closing a connection does not guarantee downstream processing stops.
07 / Privacy & pricing
Less data. A simpler agreement.
The intended public API will process text in request memory, apply identifier redaction before external AI analysis, and avoid storing resume content or responses. Rule-based redaction may miss identifying details. Unlike browser file extraction in the playground, a direct API submission sends your supplied text to Signal’s server; remove unnecessary personal data before sending it.
Your integration controls what it logs and stores. Do not log request bodies, credentials, or evidence excerpts by default. Provider identification, retention arrangements, and contractual disclosures must be finalised before public launch; this draft is not a compliance certification.
Planned flat-rate pricing. API access included. The same analysis and rate for every business size. The current playground is free.
Before launch: implement authentication and key management, validate this contract at the public boundary, set quotas and usage accounting, and finalise billing/retry semantics. Batch jobs, webhooks, persistent history, and file-upload endpoints are outside this v1 proposal.
Try the evaluation experience →