Everything needed to submit resumes, track parse jobs, fetch structured results, and receive parse events. All endpoints are project-scoped and authenticated with a project API key.
Use https://cvault.tech as the production API origin. The /v1 parser API is served on this host. The examples use $CVAULT_API_URL and $CVAULT_API_KEY as environment placeholders.
Successful responses use the envelope { data, meta } with meta.api_version and meta.request_id. Most errors use application/problem+json; direct multipart upload validation has a separate JSON body.
Create a project and an API key in the console, then send the key as x-api-key. Keys are environment-bound: cv_test_… for test projects and cv_live_… for live projects.
Example
x-api-key: cv_live_<your-key>
Public parser scopes: parse.read, parse.write, usage.read, schema.read and webhook.manage. A .write scope grants the matching .read operation. Keep the key on your backend; bearer tokens, cookies and query-string keys do not authenticate /v1.
Use an API-enabled workspace. Owners and managers create test or live projects at Projects and keys at API keys. The raw key is shown once; store it in a secret manager. Key management can require an MFA step-up. Rotation revokes the previous key immediately. A test prefix identifies the project environment; it does not mean parsing is simulated or unlimited.
Quickstart
Submit a resume and read the returned job ID. Parsing is asynchronous: poll GET /v1/parse-jobs/{job_id} until the status is terminal, or subscribe to parse webhooks.
These examples submit a file; they do not wait for parsing to finish. Python needs requests; Node needs Node 20+ and an ESM file (.mjs). Store the job ID, then poll with results included:
Example
curl-sS"$CVAULT_API_URL/v1/parse-jobs/<job_id>?include=results&limit=50"\-H"x-api-key: $CVAULT_API_KEY"# After parsing is terminal, retrieve later pages separately:curl-sS"$CVAULT_API_URL/v1/parse-jobs/<job_id>/results?limit=50"\-H"x-api-key: $CVAULT_API_KEY"
Read every file outcome
Stop on succeeded, failed, cancelled, timed_out or expired; erasure adds erasing and erased. Nonterminal polls omit results. A succeeded job can contain failed files: inspect every item. Use a bounded polling deadline, honor Retry-After, and keep the original idempotency key if an upload response is lost. See the parsing guide for recovery.
Python and Node SDKs
SDK access
The official clients submit a single file, poll the job and return its projected data. Python supports synchronous and asynchronous clients (Python 3.10+); the Node client requires Node 20+ and runs on your backend. Use the HTTP examples above for publicly available onboarding. SDK installation below requires authorized access to a source checkout; a public package download is not verified.Contact CVault about SDK access before depending on these clients.
Only with an authorized SDK source checkout
python-mpipinstall./sdks/python# Node package: build before installing locallynpm--prefixsdks/typescriptcinpm--prefixsdks/typescriptrunbuildnpminstall./sdks/typescript
import osfrom cvault_sdk import CVaultwith CVault(api_key=os.environ["CVAULT_API_KEY"]) as client: data = client.parse("resume.pdf", idempotency_key="candidate-42-revision-7")print(data.get("contact"))
Store your own idempotency key per file revision to recover across process restarts. SDK polling defaults to 300 seconds; a polling timeout does not cancel the server job. Recover with the job ID carried by timeout or post-submission errors. The single-file helpers do not submit batches; use the HTTP flows below for batches and page through all results.
Endpoints
Examples use synthetic identifiers and illustrative values; they show valid response subsets, not a complete schema or plan allowance. Replace every placeholder before making a request. JSON examples require content-type: application/json and your x-api-key header.
GET
/v1/schema
Read the parser response schema
Required scope: schema.read
Returns the parser version, mode, top-level field names and advertised evidence modes. This is a capability summary, not a nested JSON Schema or OpenAPI document. Responses are marked no-store.
No request parameters. Send your project API key in the x-api-key header.
Integration notes
Standard mode only; precision_enabled is false.
Advertised evidence modes do not establish a selectable full-evidence response contract. The current submission path does not expose an evidence-mode switch. Inspect the returned projection and use the workspace schema when applicable.
Submits one or more resume files in a single multipart request. `POST /v1/parse-jobs` is an alias of this endpoint. Parsing is asynchronous: the response returns a job ID that you poll or receive by webhook.
Request parameters
Idempotency-Keystringheaderrequired
8–200 characters. Alternative: X-CVault-Idempotency-Key or the idempotency_key form/JSON field. All supplied values must agree.
files[]file[]formrequired
One or more files as multipart/form-data. Send each file with its filename and content type. File, batch and account limits apply.
job_descriptionstringform
Optional job context. Upload sessions limit this to 50,000 UTF-8 bytes.
parse_optionsJSON stringform
Standard parser options. Upload sessions limit normalized options to 20,000 bytes; precision, LLM-extra and evidence-mode switches are not exposed.
parser_workspace_idUUIDform
Bind an accessible processing workspace. Its configuration revision is saved with the job. See the workspace guide for API restrictions.
webhook_subscription_idUUIDform
Select an active subscription in the same project/environment. Without it, matching active project subscriptions are used.
client_metadataJSON stringform
String values only: at most 16 pairs, 64-byte keys, 256-byte values and 2,048 serialized UTF-8 bytes in total.
Integration notes
Use multipart/form-data; repeat files[] for every file. Let your HTTP library set the boundary.
Metadata: at most 16 string pairs, nonempty keys up to 64 UTF-8 bytes, values up to 256 bytes and a serialized object up to 2,048 bytes. Do not put resume content, secrets or callback URLs in metadata.
Idempotency is required. Retry the same file bytes, form fields and operation with the same key. Changed content returns 409 idempotency_conflict.
New asynchronous jobs return 202; a completed or cached submission can return 200. Store data.job_id in either case. Examples show a subset of the response; dispatch metadata and candidate_shells can also be present.
Declare whole files, upload each file independently to its signed PUT URL, then complete the session. This separates upload from parsing; it is not a chunked resumable-upload protocol.
Request parameters
Idempotency-Keystringheaderrequired
8–200 characters. Alternative: X-CVault-Idempotency-Key or the idempotency_key form/JSON field. All supplied values must agree.
filesobject[]bodyrequired
Declare 1–1,000 files. Each needs a valid filename and positive size_bytes; provide content_type for the upload. Actual size must match the declaration exactly.
job_descriptionstringbody
Optional job context. Upload sessions limit this to 50,000 UTF-8 bytes.
parse_optionsobjectbody
Standard parser options. Upload sessions limit normalized options to 20,000 bytes; precision, LLM-extra and evidence-mode switches are not exposed.
parser_workspace_idUUIDbody
Bind an accessible processing workspace. Its configuration revision is saved with the job. See the workspace guide for API restrictions.
webhook_subscription_idUUIDbody
Select an active subscription in the same project/environment. Without it, matching active project subscriptions are used.
client_metadataobjectbody
String values only: at most 16 pairs, 64-byte keys, 256-byte values and 2,048 serialized UTF-8 bytes in total.
Integration notes
Returns 201. Send application/json and a valid idempotency key. Each file declaration includes filename, positive size_bytes and content_type.
The actual object size must match size_bytes. A mismatch rejects completion with HTTP 415 unsupported_file; object_size_mismatch is an internal rejection reason.
Use each upload target once for its declared file. Do not send your CVault API key to the storage URL, and treat that signed URL as a temporary secret.
Complete before accept_before (10 minutes). The provider token lasts 7,200 seconds, but this does not extend the session acceptance deadline.
Upload sessions allow at most 1,000 files, 10 MiB per file and 50 MiB total by default. Admission and account limits can impose lower limits.
Validates the uploaded objects, scans them, and submits the batch for parsing. Completion is idempotent per session; repeating it returns the same accepted job response once the job is bound.
Request parameters
session_idstringpathrequired
The session ID returned by declaration.
Idempotency-Keystringheaderrequired
8–200 characters. Alternative: X-CVault-Idempotency-Key or the idempotency_key form/JSON field. All supplied values must agree.
Integration notes
A valid idempotency key is required for completion. The body may be omitted only when the key is supplied by Idempotency-Key or X-CVault-Idempotency-Key. Use a separate key from session creation.
Returns 202 when accepted (or 200 for a completed outcome). Repeating the same completion returns the bound job. Completion validates objects and malware scan evidence.
Unknown IDs return 404; completion already running returns 409; expired, cancelled or rejected sessions return 410. Time-budget exhaustion can return 408. Handle the actual problem code and retryable flag.
Read job progress. Stop polling on succeeded, failed, cancelled, timed_out, expired or erased. Erasure reports erasing until cleanup completes.
Request parameters
job_idstringpathrequired
The job ID returned by submission.
includestringquery
Set to results to include a result page when parsing is terminal. Nonterminal and erasure responses omit the page.
limitintegerquery
1–100; defaults to 50.
cursorstringquery
Pass the opaque next_cursor from the previous page. Keep the same key; results pages also require the same limit.
Integration notes
Statuses: queued, running, succeeded, failed, cancelled, timed_out, expired, erasing, erased. A succeeded batch can contain failed or duplicate files; inspect each result.
done counts processed files including failures and timeouts. estimated_seconds_remaining can be null and is not a latency guarantee.
Add ?include=results to include a results page when parsing is terminal. limit and cursor apply to that page. Nonterminal, erasing and erased status responses omit the page.
Returns the parsed documents for a job, page by page. Each item contains the candidate data, per-file success state, and duplicates detected in the batch.
Request parameters
job_idstringpathrequired
The job ID returned by submission.
limitintegerquery
1–100; defaults to 50.
cursorstringquery
Pass the opaque next_cursor from the previous page. Keep the same key; results pages also require the same limit.
Integration notes
limit is 1-100, default 50. Pass next_cursor as the cursor query parameter; keep the same limit and API key. Cursors are opaque and bound to the job, project, environment and key.
The outer success flag describes retrieval. Each item has status (succeeded or failed), success, filename, data and a safe error when present. Pending items may have no data; wait for a terminal job before treating results as final.
Duplicate items have duplicate: true, data: null and success: false. They are not newly parsed documents. duplicates describes the current page.
parses_used and parses_limit are workspace parse-quota counters, not the organization parser-credit balance. A null parses_limit means an unbounded plan quota.
Read every page until next_cursor is null. Canonical parser data is extensible; the example shows only a subset of fields, not a complete nested schema.
Fences queued or running parser work, deletes accepted source objects, and erases durable results and cached copies. The operation is idempotent. Poll the job until `status` is `erased`; results are unavailable while erasure is pending.
Request parameters
job_idstringpathrequired
The job ID returned by submission.
Integration notes
Returns 200 with status: erased when cleanup is complete, or 202 with status: erasing and cleanup_pending: true while reconciliation retries. Poll until erased.
Once accepted, results return 410 parse_job_erasure_in_progress. Cancellation is not erasure. The idempotent DELETE needs no idempotency header.
Erasure covers this job source/results/cache. Operational audit and metering identities remain. Separately persisted processing-workspace documents, exports and receiver copies require separate lifecycle handling; do not assume organization-wide deletion.
Lists per-document metering events for this project, newest first. This is an event ledger, not a monthly allowance or parser-credit balance endpoint.
Request parameters
limitintegerquery
1–100; defaults to 50.
cursorstringquery
Pass the opaque next_cursor from the previous page. Keep the same key; results pages also require the same limit.
Integration notes
limit is 1-100 (default 50); send cursor=<next_cursor> to continue.
request_id in a usage event references the request ledger row; /v1/requests exposes its correlation request_id separately.
document_units records document usage. charged_units belongs to a separate developer billing ledger; the current metering writer records zero charged units. This does not make parsing free: organization parser credits are separate.
Additional fields include event_key and estimated_compute_usd when present. Estimates are not invoice prices.
Lists project request ledger outcomes, HTTP status codes, job IDs, document counts and timing metadata. Use it to reconcile submissions by request and job identity.
Request parameters
limitintegerquery
1–100; defaults to 50.
cursorstringquery
Pass the opaque next_cursor from the previous page. Keep the same key; results pages also require the same limit.
Integration notes
Returns sanitized request ledger records, newest first. id identifies the ledger row; request_id is the correlation ID. The example shows a subset of available outcome and timing fields.
Internal response payloads, fingerprints, storage paths, hashes and secrets are excluded. Raw idempotency keys are not returned by this endpoint.
Use limit (1-100, default 50) and cursor=<next_cursor>. Keep cursors opaque and use the same project/key.
Creates a project/environment subscription and returns secret once in the 201 creation response. Store it securely to verify deliveries. Console organization endpoints are a distinct scope.
Request parameters
target_urlstringbodyrequired
A publicly reachable HTTPS URL without embedded credentials. Private, loopback and metadata-service destinations are blocked.
event_typesstring[]bodyrequired
One or more supported events: parse.accepted, parse.completed, parse.failed, parse.timed_out or parse.cancelled.
Integration notes
Use a publicly reachable HTTPS endpoint without URL credentials. Private, loopback and metadata-service destinations are blocked; redirects are not followed.
Supported events: parse.accepted, parse.completed, parse.failed, parse.timed_out, parse.cancelled. These are job transitions; inspect individual results after completion.
Use webhook_subscription_id on a submission to select an active subscription in the same project/environment. Otherwise matching active project subscriptions are used. Request-level callback URLs are rejected.
There are no public /v1 list, update, test or secret-rotation routes for these subscriptions. Do not confuse console organization endpoint controls with the developer project API.
Submission and upload-session mutations require Idempotency-Key or its documented alternatives. Cancellation and erasure use idempotent DELETE requests without that header.
Required for multipart submission, upload-session creation and completion. Use Idempotency-Key, X-CVault-Idempotency-Key, or the idempotency_key form/JSON field. All supplied values must match; otherwise 400 idempotency_key_required.
Keys are 8-200 characters, begin with a letter or digit and then use letters, digits, dot, underscore, colon or hyphen.
Within a project, replaying the same key, operation, content and fields returns the recorded outcome. Keep the key across timeouts and process restarts; recorded responses may retain their original request ID.
Changed content or fields with the same key returns 409 idempotency_conflict. An in-progress replay returns 409 idempotency_in_progress with Retry-After.
Use distinct keys for session creation and completion. Cancellation and erasure are idempotent DELETE operations and need no idempotency header.
Three independent buckets in a 60-second window. Submission shares key/project/workspace counters; job reads and metadata use separate per-key counters. The window is 60 seconds.
429 rate_limit_exceeded with Retry-After; the error body is application/problem+json.
Bucket
Operations
Allowance
Submission
POST and DELETE
Configured base limit; shared key/project/workspace counters
Read
GET job status and results
10 times base limit, capped at 1,200/minute per key
Metadata
GET schema, usage and requests
2 times base limit, capped at 1,200/minute per key
Read the actual X-RateLimit-Limit for the current operation rather than assuming a plan value. X-RateLimit-Reset is the value 60 in seconds, not a Unix timestamp. Admission concurrency, document quotas and parser credits are additional checks independent of these buckets.
File rules
Rule
Value
Supported extensions
.pdf, .docx, .doc, .txt, .png, .jpg, .jpeg
Maximum file size
10 MiB per file
Maximum batch size
50 MiB per request (configurable per deployment)
Maximum upload-session files
1,000
Filename
At most 255 characters; no path separators, NUL, CR or LF
The batch byte limit measures file contents; multipart framing has a separate bounded allowance. Direct multipart batches also pass deployment admission and account limits; do not assume that 1,000 files is a universal direct-upload cap. Filenames must be nonempty and cannot be . or .. . Extension alone is insufficient: content, type, document resource limits and malware scans are validated.
Errors
Most errors are application/problem+json with a stable code, a retryable flag, and the request ID for support.
Example error
{"type": "https://api.cvault.app/problems/quota_exceeded","title": "Quota Exceeded","status": 403,"code": "quota_exceeded","detail": "The project allowance has been exceeded.","retryable": false,"request_id": "req_8f1c...","field_errors": []}
Upload validation uses a different error body
Direct multipart validation is an exception: HTTP 413 (size/resource limits), 415 (invalid content/type) or 503 (scanner unavailable) returns a direct JSON body before admission, without a job or data/meta envelope. Inspect error_code and validation_results. Generic validation failures may have only per-file codes. Size/type errors require corrected input; scanner outages are retryable with the same submission key.
The table covers common transport errors, not every possible validation or admission reason. Read HTTP status, code (or error_code), retryable and Retry-After together. Preserve X-Request-Id for support. The problem type URI identifies the error category; it is not the API origin.
Code
Status
Meaning
api_key_required
401
The x-api-key header is missing.
invalid_api_key
401
The API key is invalid or no longer active.
project_key_required
403
The key is not bound to an active test/live project.
api_key_scope_required
403
The key lacks the scope required by the endpoint.
api_access_not_enabled
403
API access is not enabled for this workspace.
quota_exceeded
403
Workspace plan quota or a project/key daily/monthly document cap is exhausted.
rate_limit_exceeded
429
The project rate limit was exceeded; honor Retry-After.
idempotency_key_required
400
A valid idempotency key was not supplied.
idempotency_conflict
409
The idempotency key was reused with a different payload.
idempotency_in_progress
409
The original idempotent request is still processing.
files_required
400
The multipart request contained no files[] parts.
unsupported_media_type
415
Use multipart/form-data or application/json as documented.
payload_too_large
413
The request body exceeds the documented limit.
upload_validation_failed
415
A file failed validation; inspect the direct multipart validation body for per-file codes and its HTTP status.
upload_session_not_found
404
The upload session does not exist for this project.
parse_job_not_found
404
The job ID is malformed, unknown or unavailable to this project.
invalid_limit
400
limit must be an integer from 1 to 100.
invalid_cursor
400
The cursor is invalid or bound to a different resource/key/environment/results-page limit.
webhook_input_invalid
422
target_url or event_types are missing or invalid.
webhook_https_required
422
Webhook targets must use HTTPS.
webhook_events_invalid
422
No supported event remains in event_types; unknown entries are filtered. Supply only documented events.
webhook_subscription_id_invalid
422
The subscription ID is malformed, inactive or unavailable in the project/environment.
precision_not_enabled
422
Only standard parser mode is available on the public V1 API.
parse_service_unavailable
503
The parser is temporarily unavailable; retry with backoff.
service_unavailable
503
The service is temporarily unavailable; retry with backoff.
insufficient_parser_credits
402
Organization parser credits are insufficient; add credits before retrying.
client_metadata_invalid
422
Metadata exceeds the documented object/string limits.
parse_options_invalid
400
Multipart parse_options must be a JSON object string.
invalid_json
400
The request body is not valid JSON.
json_body_required
400
A JSON object is required.
request_destination_forbidden
422
Request-level callback or webhook destinations are unsupported.
parse_conflict
409
The operation conflicts with the current job or session state.
parse_job_erasure_in_progress
410
Source and results are being erased or have been erased.
unsupported_file
415
An uploaded session object failed validation, including declared-size mismatch.
parse_timeout
408
Upload-session validation or completion exceeded its time budget.
rate_limiter_unavailable
503
Rate-limit enforcement is unavailable; honor Retry-After.
parser_credit_unavailable
503
Credit accounting is temporarily unavailable.
parser_erasure_unavailable
503
Retry the same erasure request to finish cleanup.
parser_workspace_id_invalid
422
Processing workspace ID is malformed or conflicts with parse_options.
parser_workspace_not_found
404
The processing workspace is unavailable to this project actor.
parser_workspace_ocr_unsupported
501
Public asynchronous workspace submissions require automatic OCR.
parser_workspace_splitting_unsupported
501
Page splitting is unsupported in the public asynchronous flow.
parser_workspace_memory_unsupported
501
Model memory is unsupported in the public asynchronous flow.
parser_workspace_auto_classify_unsupported
501
Automatic classification is unsupported in the public asynchronous flow.
parser_workspace_persistence_unavailable
503
Retry results retrieval to finish saving the workspace document.
Before production integration
Keep API keys and signed upload URLs out of browsers, URLs, source control and logs.
Use an API-enabled project with sufficient credits, scopes and document allowance.
Persist submission keys and job IDs; recover ambiguous uploads without generating new keys.
Handle partial failures, duplicate files, every results page and a bounded polling deadline.
Authenticate webhook bytes, persist delivery IDs atomically and durably enqueue before acknowledging.
Use erasure for deletion and wait for erased; cancellation alone retains completed documents.
Use /v1 for this parser contract. The separate /api/v1 platform API and its OpenAPI document are not this API.