Developer Docs
Let your AI agents push career data into AskCV. Import knowledge entries, work experience, skills, projects, and more — all staged for your review before going live.
Go to Settings → API Keys in your AskCV dashboard. Create a new token with agent type and select the scopes you need: agent:read for exporting data, agent:write for importing.
Include your token in every request as a standard Bearer token. The token is shown once at creation and cannot be retrieved later — store it securely.
curl -X POST https://askcv.ai/api/v1/capabilities/import.createBatch \
-H "Authorization: Bearer askcv_agt_<token>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: <unique-per-attempt>" \
-d '{"input": {"items": [...]}}'Every capability takes its arguments under a single inputkey — the body is {"input": {…}}, never the arguments at the top level. A capability that takes no arguments still needs a body: {"input": {}}. Posting nothing at all fails JSON parsing and returns 400 INVALID_JSON.
Writes require an Idempotency-Key header. It is a required intent marker rather than a replay key: dedupe is derived from the payload, so an identical body collapses onto the same batch whatever the header says, and a reused header with a changed body is a new write.
| Type | Prefix | Default scopes | Use case |
|---|---|---|---|
| extension | askcv_ext_ | extension | Browser extension |
| agent | askcv_agt_ | agent:read, agent:write, agent:query | AI agents (Claude, ChatGPT, etc.) |
| mcp | askcv_mcp_ | mcp | MCP server connections |
Four capabilities cover the import/export workflow. Every capability is invoked the same way — POST /api/v1/capabilities/{name} with a JSON body — and answers with a JSON envelope.
All twelve stopped responding on 4 August 2026 and now return 410 Gone naming their replacement, with no authentication and no data access left behind them. Build against the generated capability surface — POST /api/v1/capabilities/{name}, with GET /api/v1/capabilities listing what your token can reach.
Most successors are scope-for-scope: they accept the same agent:read / agent:write / agent:query token the endpoint they replace required. Three do not, and they are the ones most likely to break a migration silently: career.ask, fit.check and profile.get each require an explicit tool:{name} grant. A broad agent:query or agent:read token — exactly what the retired endpoints ran on — reaches them with a 403 SCOPE_DENIED, not a result. Select the capability by name when you create the token.
| Retired endpoint | Capability | What changes |
|---|---|---|
| POST /api/agent/import | import.createBatch | Same body and scope. Writes now require an Idempotency-Key header. |
| GET /api/agent/import/[batchId] | import.getBatchStatus | Batch id moves from the path into the JSON body. |
| GET /api/agent/export/[domain] | export.getDomain | Domain, cursor and limit move into the JSON body. No format=jsonld — read the JSON projection. |
| GET /api/agent/export/profile | export.getProfile | Same column allow-list. No format=jsonld — read the embedded sections via export.getDomain. |
| POST /api/agent/query | career.ask | Same body and hourly budget, but agent:query alone no longer reaches it — grant tool:career.ask explicitly. |
| POST /api/agent/fit-check | fit.check | Same body and hourly budget, but agent:query alone no longer reaches it — grant tool:fit.check explicitly. |
| POST /api/agent/evidence | search_evidence (alias: evidence.search) | Same body and scope. |
| GET /api/agent/goals | get_career_goals (alias: goals.list) | Same scope. |
| GET /api/agent/depth | get_agent_depth (alias: depth.get) | Same scope. |
| GET /api/agent/coverage | get_coverage_score (alias: coverage.getScore) | Same scope. |
| GET /api/agent/profile | profile.get | Narrower nested payload, and needs an explicit tool:profile.get grant — see below. |
| GET /api/agent/health | /openapi.json | Discovery was unauthenticated, so its successors are too: this document, plus /api/health for liveness. |
It stopped responding on 4 August 2026 and now returns 410 Gone. The field-level differences below still matter — they are what a migrating caller has to account for.
The replacement returns a narrower, nested digest — fields live under profile rather than at the top level, and these are not carried over: careerGoal, urgencyLevel, stats, and skillNames. That narrowing is the point of the migration, not a gap waiting to be filled.
// what /api/agent/profile used to return (RETIRED)
{
"name": "Jane Smith",
"title": "Staff Engineer",
"headline": "Building developer tools at scale",
"location": "San Francisco, CA",
"careerGoal": "...", // gone
"urgencyLevel": "...", // gone
"stats": { ... }, // gone
"skillNames": [ ... ] // gone
}It also requires an explicit tool:profile.get grant — a coarse agent:read token will not reach it. Select the capability when you create the token.
The retired export routes could return a Schema.org rendering — an ItemList per domain, or a Person document with experience, education, skills and certifications embedded — selected by a query parameter and signalled with an application/ld+json content type. Both halves of that are transport choices a single uniform envelope cannot express, so every capability answers as JSON on one media type.
Nothing is unreachable as a result — the successors disclose strictly less framing, never less data. The sections the Person document embedded are the same rows export.getDomain returns for experience, education, skill and certification, so a client that wanted JSON-LD now builds it from those.
Eleven importable career domains. Each item in a batch specifies a domain and a payloadmatching that domain's schema. profile_update marks every field optional but requires at least one of them.
Two domains read back differently than they import. Exporting performance_review or pipeline_job through export.getDomain currently returns FEATURE_UNAVAILABLE: the only surfaces those rows appear on are not yet public, and the export refuses rather than returning an empty page that would read as “you have none”. Importing them works and the data is kept; the export restores itself when those surfaces open.
Connect your AI coding assistant to AskCV via the Model Context Protocol. Three tools: import_career_data, get_import_status, and read_career_data.
In your AskCV dashboard, go to Settings → API Keys and create a token with mcp type.
Add the following to your .mcp.json (Claude Code) or equivalent MCP config file. Replace the placeholder token with yours.
{
"mcpServers": {
"askcv": {
"url": "https://askcv.ai/api/mcp",
"headers": {
"Authorization": "Bearer askcv_mcp_YOUR_TOKEN_HERE"
}
}
}
}| Tool | Description |
|---|---|
| import_career_data | Submit career items for staged import (the MCP twin of the import.createBatch capability) |
| get_import_status | Check the approval status of a previous import batch |
| read_career_data | Read existing career data for a domain (dedup check) |
These three are the headline import + dedup tools. Your MCP token also unlocks a broader read surface over the same endpoint: the export + batch-status reads (export.getDomain, export.getProfile, import.getBatchStatus), and — with the agent:query scope — grounded Q&A (ask_career_question), evidence search, and the coverage + agent-depth scores. The granular-consent reads — kb.find, profile.get, pipeline.listJobs and their siblings — are not reachable with an MCP token at all: they require a per-tool tool:{name} grant, which only agent-type tokens can carry. Use an agent token and the REST capability surface for those. Every read returns the same flat JSON payload in the tool result, so you can parse content[0].text directly. Discover the full list via the MCP tools/list call. This endpoint also accepts the legacy import + career-setter tools (import_career_data, set_career_progression, …), so an MCP token is read + import capable, not read-only. The granular knowledge / profile / pipeline write-pack (with per-tool scopes, approval, and undo) is served only on the OAuth-secured /api/mcp/write surface.
Example workflow
“After a performance review, ask your AI assistant to extract accomplishments and push them to AskCV. They land in your review inbox and become knowledge base entries on approval.”
Sync coaching notes
“Have your coding agent create coaching action items from code review feedback or 1:1 meeting notes.”
Export and dedup
“Read existing skills before importing new ones. The export capabilities let agents check what you already have.”
Every call is rate-limited per tenant. Exceeding a limit returns a 429 response with a retryAfterMs field. Where a per-capability budget is shared across transports, the table says so — holding two credentials does not then buy two budgets.
| Endpoint | Limit | Scope |
|---|---|---|
| Every capability call | 60 requests/hour | Per tenant, per transport |
| career.ask | 30 requests/hour | Per tenant, shared by REST, MCP and A2A |
| fit.check | 10 requests/hour | Per tenant, shared by REST, MCP and A2A |
| import.createBatch | 20 batches/hour | Per tenant, shared by REST and the MCP capability surface (the legacy import_career_data tool has its own bucket) |
Batch size cap: 100 items per import.createBatch call. Export pagination: max 100 items/page (default 50).
01
Agent submits
Your AI agent sends a POST request with career data items. Each item is validated against its domain schema.
02
Staged for review
Valid items land in your import inbox as pending. Invalid items are returned in the error response.
03
You approve
Review each item in your dashboard. Approve individually or in bulk. Rejected items are discarded.
04
Data goes live
Approved items flow through ingestion pipelines: PII detection, embeddings, AI analysis. They become part of your career knowledge base.
Create your AskCV account, generate an API key, and start importing career data in under 5 minutes.