AI Resilience API & MCP
API v2.1Free, public API for AI career resilience data. No API key required. Rate limited to 100 requests per minute per IP.
Attribution Required
This data is free to use, share, and adapt, including commercially, under CC BY 4.0. The license requires that you credit the source with a visible link back to airesilience.org. Paste one of these wherever you display the data:
<a href="https://www.airesilience.org">AI Resilience Report</a> by <a href="https://www.careervillage.org">CareerVillage.org</a>, licensed under <a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.AI Resilience Report by CareerVillage.org, licensed under CC BY 4.0. https://www.airesilience.orgEvery API response also carries an attribution object with these values, so you can render the credit straight from the payload. Linking to the specific career page you are quoting is welcome and works as attribution too.
Full Dataset Download
Bulk CSV export of the latest quarterly snapshot — all scored occupations, sub-scores, and per-source values. Licensed under CC BY 4.0.
1,571 careers · Snapshot: 2026-10-07
Geo Dataset Download
Bulk CSV of the local layer — one row per occupation per metro/nonmetro area (~450k rows) with workers, median wage, location quotient, and the national comparison figures. May 2025 OEWS. Kept separate from the main dataset so that file stays small. Licensed under CC BY 4.0.
API Playground
This API uses 2019 SOC codes. You can look up codes at bls.gov/soc.
Resilience scores are generated by the AI Resilience Model v1.5 (returned as data.airm_cv.version). See the Changelog for version history.
Single-Career Endpoint
Path Parameter
| Parameter | Type | Description |
|---|---|---|
| code | string | SOC code in format XX-XXXX or XX-XXXX.XX |
Query Parameters
All parameters are optional. area and county are mutually exclusive.
| Parameter | Type | Description |
|---|---|---|
| area | string | OEWS area ID (5-digit CBSA for metros, 6-7 digit code for nonmetro regions). Adds a local block with that area's workers, median wage, and location quotient. Find IDs via the Area Search Endpoint. |
| county | string | 5-digit county GEOID (2-digit state FIPS + 3-digit county FIPS, e.g. 25025 for Suffolk County, MA). Resolves to the county's OEWS area, then behaves exactly like area. Handy when you already have a location from a geocoder. |
| band | string | Restrict expertise.bands to one experience band: entry, mid, or senior. Omitted, all three are returned. |
Response Format
Success (200)
Fields are grouped by concern. All numeric scores are on a 0-1 scale unless otherwise noted. Any field can be null when the underlying data is unavailable for that occupation.
Every successful response also carries a top-level attribution object (required, text, url, license, sources) so you can render the required credit directly from the payload. See Attribution.
Core
| Field | Type | Description |
|---|---|---|
| data.code | string | SOC code |
| data.name | string | Career name |
| data.nameShort | string | Short display name |
| data.slug | string | URL slug used on airesilience.org |
| data.level | string | SOC hierarchy level: "major", "minor", "broad", or "detailed" |
| data.description | string | Plain-text occupation description |
| data.url | string | Link to the full career report page |
| data.lastUpdated | string | Date (YYYY-MM-DD) of the latest data snapshot |
aiResilience
| Field | Type | Description |
|---|---|---|
| data.aiResilience.score | number | Combined AI resilience score (0-1, higher = more resilient) |
| data.aiResilience.label | string | One of: "Highly Resilient" (80.1-100%), "Resilient" (65.1-80%), "Mostly Resilient" (50.1-65%), "Somewhat Resilient" (35.1-50%), "Not Very Resilient" (22.1-35%), or "Vulnerable" (0-22%) |
| data.aiResilience.confidence | string | Confidence level (High, Medium-high, Medium, Low-medium, Low) |
| data.aiResilience.confidenceScore | number | null | Numeric confidence (0-100) behind the confidence level: points for the number of sources covering the career plus points for how tightly those sources agree |
| data.aiResilience.explanation | string | Human-readable explanation of the resilience label |
airm_cv (AI Resilience Model, CareerVillage)
| Field | Type | Description |
|---|---|---|
| data.airm_cv.version | string | AI Resilience Model version (e.g., "v1.5"). See the Changelog for version history. |
| data.airm_cv.percentile | number | CareerVillage internal model percentile (0-1) |
| data.airm_cv.label | string | "High", "Medium", or "Low" |
| data.airm_cv.rawScore | number | Raw weighted percentile from the CV model |
sources
Per-source signals that feed the combined resilience score. Percentiles are 0-1 within their respective populations.
| Field | Type | Description |
|---|---|---|
| data.sources.anthropic | object | Anthropic Economic Index: percentile, rawScore |
| data.sources.microsoft | object | Microsoft AI Applicability: percentile, rawScore |
| data.sources.wrtmj | object | Will Robots Take My Job: percentile, label, rawRiskPercent, growth, volume |
| data.sources.openai | object | OpenAI Signals usage-based exposure: percentile, rawScore (null where uncovered) |
| data.sources.althoff | object | Althoff wage-bill exposure: wageBillPercentile, rawScore (null where uncovered) |
| data.sources.manning | object | Manning adaptive capacity: adaptiveCapacityPercentile, adaptiveCapacityRawScore (null where uncovered) |
| data.sources.lted_blsOpportunity | object | BLS opportunity (the LTED subscore): score, label |
subscores
| Field | Type | Description |
|---|---|---|
| data.subscores.meaningfulHumanContribution | object | score (0-1), label (High/Medium/Low) |
| data.subscores.sustainedEconomicOpportunity | object | score (0-1), label (High/Medium/Low) |
stepsToTake
| Field | Type | Description |
|---|---|---|
| data.stepsToTake | string[] | AI-generated suggested actions for students. Empty array when not available. |
tasks
Populated for detailed occupations only. Sorted by automationLikelihood ascending (most resilient first).
| Field | Type | Description |
|---|---|---|
| data.tasks[].id | string | O*NET task ID |
| data.tasks[].task | string | Task description |
| data.tasks[].taskType | string | "Core" or "Supplemental" |
| data.tasks[].automationLikelihood | number | 0-1; lower = more resilient |
| data.tasks[].resilienceScore | number | Convenience: 1 − automationLikelihood |
| data.tasks[].expertiseLevel | number | 0-1 expertise the task requires (Autor & Thompson anchors; relative to the occupation). The raw input to data.expertise, so you can rebuild the career-level numbers yourself. |
| data.tasks[].analysisDate | string | Date the automation estimate was generated (ISO 8601) |
expertise (Experience Outlook — added in v1.1)
Career-level expertise shift derived from the per-task tasks[].expertiseLevel and tasks[].automationLikelihood scores — the same math behind the site's Experience Outlook panel.
| Field | Type | Description |
|---|---|---|
| data.expertise | object | null when no tasks carry both automation and expertise scores (the career page hides its Experience Outlook panel in the same case) |
| data.expertise.deltaExpertise | number | Career-level ΔExpertise: average expertise of tasks surviving automation minus average expertise of all tasks. Positive = AI removes low-expertise tasks (the barrier to entry rises); negative = AI reaches the expert tasks. null when no tasks survive the automation threshold |
| data.expertise.deltaExpertisePercentile | number | Percentile rank (0-100) of the ΔExpertise value across all scored detailed careers |
| data.expertise.routine | object | For the career's routine tasks (lowest-expertise slice): resilience (weighted avg, 0-1) and erosion (weighted share at/past the automation threshold, 0-1) |
| data.expertise.expert | object | Same two metrics for the career's expert tasks (highest-expertise slice) |
| data.expertise.forecast | object | Ten-year outlook vs the average occupation. wage and employment each carry center / low / high (±1 s.e.); unit spells out the scale; capped is true when the exposure exceeded ±2 SD and was clamped. null when ΔExpertise is undefined |
| data.expertise.scoredTaskCount | number | Tasks carrying both automation and expertise scores |
| data.expertise.method | string | How the numbers are produced (Autor & Thompson 2025, Table 8 coefficients) |
| data.expertise.caveat | string | Out-of-sample disclosure: the coefficients were estimated on 1980-2018 computerization, and applying them to AI-era exposure is a transfer. Shipped in the payload because the site disclosures it too |
| data.expertise.distributionVintage | string | Build date and career count of the percentile distribution, e.g. "2026-09-29 (928 careers)". Percentiles can shift when the distribution is rebuilt after each quarterly rescoring |
expertise.bands
| Field | Type | Description |
|---|---|---|
| data.expertise.bands | object | Keyed by band id (entry, mid, senior). All three by default; just one when ?band= is passed. Bands are relative to each career: entry = the career's least-expert third of tasks, senior = the top third |
| ...bands.*.label | string | "Entry", "Mid", or "Senior" |
| ...bands.*.personalExposure | number | Weighted avg automation likelihood over the band's task portfolio (its tercile plus everything below it), 0-1 |
| ...bands.*.careerAvgExposure | number | Weighted avg automation likelihood over all scored tasks, for comparison |
| ...bands.*.rungErosion | number | Weighted share of the band's defining tasks at/past the automation threshold, 0-1 |
| ...bands.*.bandOutlookModifier | number | Positive = this band's outlook is better than the career's headline number; negative = worse |
| ...bands.*.sentiment | string | "positive", "neutral", or "negative" — the same verdict the career page's Experience Outlook badge shows |
| ...bands.*.definingTaskCount | number | Number of tasks in the band's defining tercile |
laborMarket
BLS employment and wage data. Employment counts are absolute (not in thousands).
| Field | Type | Description |
|---|---|---|
| data.laborMarket.medianWage | number | string | Annual median wage in USD. BLS OEWS national median where published (the same figure shown on career pages); falls back to the Employment Projections wage, which can be a capped string like ">= $239,200" |
| data.laborMarket.medianWageSource | string | Where medianWage came from: "oews_national" or "employment_projections" (fallback) |
| data.laborMarket.employment2024 | number | Total jobs in 2024 |
| data.laborMarket.employment2034 | number | Projected total jobs in 2034 |
| data.laborMarket.employmentChangePctBLS | number | Projected % change in employment 2025-2035 |
| data.laborMarket.annualOpeningsBLS | number | Projected average annual openings |
| data.laborMarket.educationRequired | string | Typical entry-level education |
| data.laborMarket.experienceRequired | string | Required work experience |
| data.laborMarket.trainingRequired | string | On-the-job training requirements |
| data.laborMarket.dataSource | string | How the Employment Projections fields (employment, openings, education, experience, training) were joined: "direct", "mapped_via_crosswalk", "aggregated_from_children", or "inherited_from_parent" |
local (Local Picture — added in v1.1)
Metro/nonmetro wage and employment for the occupation, from BLS OEWS. Populated when the request passes ?area= or ?county=. For the full per-area table, use the Local Areas Endpoint.
| Field | Type | Description |
|---|---|---|
| data.local | object | Without ?area= or ?county=, just { available, vintage } — available says whether OEWS publishes this occupation, so you know whether asking for an area will return data. With a location param, the full block below |
| data.local.area | object | The resolved area: code, title, state, type ("metro" or "nonmetro") |
| data.local.workers | number | Total employment for this occupation in the area. null = BLS-suppressed, which is meaningful — never coerced to zero |
| data.local.medianWage | number | Annual median wage in the area, USD |
| data.local.locationQuotient | number | Occupation concentration vs the nation (1.0 = same share of local jobs as nationally) |
| data.local.national | object | National workers and medianWage for comparison (BLS-published national figures, not an average of areas) |
| data.local.vintage | string | OEWS release the numbers come from, e.g. "May 2025 OEWS" |
hierarchy
SOC hierarchy relationships. Each reference is a minimal {code, name, slug, url} object.
| Field | Type | Description |
|---|---|---|
| data.hierarchy.parents.major | object | SOC Major Group parent |
| data.hierarchy.parents.minor | object | SOC Minor Group parent |
| data.hierarchy.parents.broad | object | SOC Broad Occupation parent |
| data.hierarchy.siblings | object[] | Related careers sharing the same parent and level |
| data.hierarchy.children | object[] | Direct children. Empty for detailed-level occupations. |
Example Response
{
"success": true,
"data": {
"code": "15-1252.00",
"name": "Software Developers",
"nameShort": "Software Developers",
"slug": "software-developers",
"level": "detailed",
"description": "Develop, create, and modify general computer applications software...",
"url": "https://www.airesilience.org/career/software-developers",
"aiResilience": {
"score": 0.62,
"label": "Mostly Resilient",
"confidence": "High",
"confidenceScore": 82,
"explanation": "Software developers..."
},
"airm_cv": {
"version": "v1.5",
"percentile": 0.45,
"label": "Medium",
"rawScore": 0.52
},
"sources": {
"anthropic": { "percentile": 0.42, "rawScore": 0.18 },
"microsoft": { "percentile": 0.38, "rawScore": 0.45 },
"wrtmj": { "percentile": 0.55, "label": "Medium", "rawRiskPercent": "65", "growth": "...", "volume": "..." },
"openai": { "percentile": 0.47, "rawScore": 0.0038 },
"althoff": { "wageBillPercentile": 0.61, "rawScore": 0.74 },
"manning": { "adaptiveCapacityPercentile": 0.58, "adaptiveCapacityRawScore": 0.63 },
"lted_blsOpportunity": { "score": 0.7, "label": "High" }
},
"subscores": {
"meaningfulHumanContribution": { "score": 0.65, "label": "High" },
"sustainedEconomicOpportunity": { "score": 0.70, "label": "High" }
},
"stepsToTake": [
"Build a portfolio of projects that show end-to-end problem solving...",
"Develop fluency with AI-assisted coding tools..."
],
"tasks": [
{
"id": "1",
"task": "Confer with systems analysts, engineers, programmers and others...",
"taskType": "Core",
"automationLikelihood": 0.18,
"resilienceScore": 0.82,
"expertiseLevel": 0.55,
"analysisDate": "2026-05-16"
}
],
"expertise": {
"deltaExpertise": 0.0215,
"deltaExpertisePercentile": 79,
"routine": { "resilience": 0.42, "erosion": 0.55 },
"expert": { "resilience": 0.71, "erosion": 0.12 },
"forecast": {
"wage": { "center": 1.8, "low": 0.9, "high": 2.7 },
"employment": { "center": -2.7, "low": -3.4, "high": -2.0 },
"unit": "percentage points per decade vs the average occupation",
"capped": false
},
"bands": {
"entry": { "label": "Entry", "personalExposure": 0.58, "careerAvgExposure": 0.44, "rungErosion": 0.67, "bandOutlookModifier": -0.043, "sentiment": "negative", "definingTaskCount": 6 },
"mid": { "label": "Mid", "personalExposure": 0.49, "careerAvgExposure": 0.44, "rungErosion": 0.33, "bandOutlookModifier": -0.021, "sentiment": "negative", "definingTaskCount": 6 },
"senior": { "label": "Senior", "personalExposure": 0.41, "careerAvgExposure": 0.44, "rungErosion": 0.17, "bandOutlookModifier": 0.043, "sentiment": "positive", "definingTaskCount": 6 }
},
"scoredTaskCount": 18,
"method": "Autor & Thompson (2025) Table 8 coefficients applied to task-level automation and expertise scores",
"caveat": "Coefficients were estimated on 1980-2018 computerization. Applying them to AI-era exposure is an out-of-sample transfer.",
"distributionVintage": "2026-09-29 (928 careers)"
},
"laborMarket": {
"medianWage": 135980,
"medianWageSource": "oews_national",
"employment2024": 1656000,
"employment2034": 1800000,
"employmentChangePctBLS": 8.7,
"annualOpeningsBLS": 140100,
"educationRequired": "Bachelor's degree",
"experienceRequired": "None",
"trainingRequired": "None",
"dataSource": "direct"
},
"local": {
"area": { "code": "14460", "title": "Boston-Cambridge-Newton, MA-NH", "state": "MA", "type": "metro" },
"workers": 42310,
"medianWage": 166090,
"locationQuotient": 1.44,
"national": { "workers": 1687890, "medianWage": 135980 },
"vintage": "May 2025 OEWS"
},
"hierarchy": {
"parents": {
"major": { "code": "15-0000", "name": "Computer and Mathematical Occupations", "slug": "computer-and-mathematical-occupations", "url": "https://www.airesilience.org/career/computer-and-mathematical-occupations" },
"minor": { "code": "15-1200", "name": "Computer Occupations", "slug": "computer-occupations", "url": "https://www.airesilience.org/career/computer-occupations" },
"broad": { "code": "15-1250", "name": "Software and Web Developers, Programmers, and Testers", "slug": "software-and-web-developers-programmers-and-testers", "url": "https://www.airesilience.org/career/software-and-web-developers-programmers-and-testers" }
},
"siblings": [
{ "code": "15-1253.00", "name": "Software Quality Assurance Analysts and Testers", "slug": "software-quality-assurance-analysts-and-testers", "url": "https://www.airesilience.org/career/software-quality-assurance-analysts-and-testers" }
],
"children": []
},
"lastUpdated": "2026-05-16"
}
}Bulk (List) Endpoint
Returns a summary list of all occupations. Useful for syncing the dataset or building filtered views client-side. Each entry is a compact summary (resilience score, label, confidence) — for the full per-occupation payload, call the single-career endpoint with the SOC code.
Query Parameters
All parameters are optional. When neither page nor pageSize is supplied, the endpoint returns the full unpaginated list.
| Parameter | Type | Description |
|---|---|---|
| page | integer | 1-indexed page number. Triggers paginated response. |
| pageSize | integer | Items per page. Default 100, max 500. Triggers paginated response. |
| level | string | Filter by SOC hierarchy level: major, minor, broad, detailed. |
| label | string | Filter by resilience label. One of the 6 labels (URL-encode spaces): "Highly Resilient", "Resilient", "Mostly Resilient", "Somewhat Resilient", "Not Very Resilient", "Vulnerable". |
Response Fields
| Field | Type | Description |
|---|---|---|
| data[] | object[] | Array of career summaries, sorted by SOC code ascending |
| data[].code | string | SOC code |
| data[].name | string | Career name |
| data[].slug | string | URL slug |
| data[].level | string | SOC hierarchy level |
| data[].url | string | Link to the career report page |
| data[].aiResilience.score | number | Combined AI resilience score (0-1, higher = more resilient) |
| data[].aiResilience.label | string | One of the 6 resilience labels |
| data[].aiResilience.confidence | string | Confidence level |
| meta.total | number | Total matching careers after filters |
| meta.lastUpdated | string | Date (YYYY-MM-DD) of the latest data snapshot |
| meta.page | number | Paginated responses only |
| meta.pageSize | number | Paginated responses only |
| meta.totalPages | number | Paginated responses only |
| meta.hasMore | boolean | Paginated responses only. True if more pages exist. |
Example Response (paginated)
GET /ext/api/careers?level=detailed&page=1&pageSize=2
{
"success": true,
"data": [
{
"code": "11-1011.00",
"name": "Chief Executives",
"slug": "chief-executives",
"level": "detailed",
"url": "https://www.airesilience.org/career/chief-executives",
"aiResilience": {
"score": 0.78,
"label": "Resilient",
"confidence": "High"
}
},
{
"code": "11-1021.00",
"name": "General and Operations Managers",
"slug": "general-and-operations-managers",
"level": "detailed",
"url": "https://www.airesilience.org/career/general-and-operations-managers",
"aiResilience": {
"score": 0.61,
"label": "Mostly Resilient",
"confidence": "Medium-high"
}
}
],
"meta": {
"total": 867,
"page": 1,
"pageSize": 2,
"totalPages": 434,
"hasMore": true,
"lastUpdated": "2026-05-16"
}
}Search Endpoint
Search occupations by title keyword. Returns the same summary shape as the bulk endpoint, ranked by where the match occurs (earlier in the title = higher rank).
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| q | string | Required. Search keyword (min 2 chars). Case-insensitive substring match against career name and short name. |
| limit | integer | Max results. Default 50, max 200. |
| level | string | Optional filter by SOC level: major, minor, broad, detailed. |
Example Response
GET /ext/api/careers/search?q=software&limit=2
{
"success": true,
"data": [
{
"code": "15-1252.00",
"name": "Software Developers",
"slug": "software-developers",
"level": "detailed",
"url": "https://www.airesilience.org/career/software-developers",
"aiResilience": { "score": 0.62, "label": "Mostly Resilient", "confidence": "High" }
},
{
"code": "15-1253.00",
"name": "Software Quality Assurance Analysts and Testers",
"slug": "software-quality-assurance-analysts-and-testers",
"level": "detailed",
"url": "https://www.airesilience.org/career/software-quality-assurance-analysts-and-testers",
"aiResilience": { "score": 0.58, "label": "Mostly Resilient", "confidence": "Medium-high" }
}
],
"meta": {
"query": "software",
"total": 7,
"limit": 2,
"truncated": true,
"lastUpdated": "2026-05-16"
}
}Tasks Endpoint
Tasks-only view of a single occupation. Returns the same tasks array as the single-career endpoint, plus minimal occupation identity. Useful when you only need task-level resilience scores and want a smaller payload.
Example Response
GET /ext/api/career/15-1252.00/tasks
{
"success": true,
"data": {
"code": "15-1252.00",
"name": "Software Developers",
"slug": "software-developers",
"level": "detailed",
"url": "https://www.airesilience.org/career/software-developers",
"tasks": [
{
"id": "1",
"task": "Confer with systems analysts, engineers, programmers and others...",
"taskType": "Core",
"automationLikelihood": 0.18,
"resilienceScore": 0.82,
"expertiseLevel": 0.55,
"analysisDate": "2026-05-16"
}
]
}
}Report Endpoint
The narrative "Career Report" for an occupation — the written analysis shown on the career page. Returns an ordered array of content sections: the AI resilience summary, the deep-research analysis paragraphs, the AI replacement verdict, and suggested actions. Section content is markdown-formatted text.
Response Fields
Alongside the occupation identity (code, name, slug, level, reportUrl), the content lives in data.careerReport, an ordered array of sections.
| Field | Type | Description |
|---|---|---|
| data.careerReport[].type | string | Section type: "Summary", "resilienceParagraph", "replacementVerdict", or "suggestedActions" |
| data.careerReport[].title | string | Display heading for the section |
| data.careerReport[].content | string | Section body as markdown-formatted text |
Example Response
GET /ext/api/career/15-1252.00/report
{
"success": true,
"data": {
"code": "15-1252.00",
"name": "Software Developers",
"slug": "software-developers",
"level": "detailed",
"reportUrl": "https://www.airesilience.org/career/software-developers",
"careerReport": [
{
"type": "Summary",
"title": "AI Resilience Summary",
"content": "Software developers are mostly resilient to AI impacts..."
},
{
"type": "resilienceParagraph",
"title": "How is AI changing Software Developers jobs?",
"content": "How is AI changing Software Developers jobs?\n\nRight now, AI in software development is leaning much more toward augmentation than full automation..."
},
{
"type": "replacementVerdict",
"title": "AI Replacement Verdict",
"content": "Will AI replace software developers? Not in the near term..."
},
{
"type": "suggestedActions",
"title": "Suggested Actions",
"content": "- Build a portfolio of end-to-end projects...\n- Develop fluency with AI-assisted coding tools..."
}
]
}
}Local Areas Endpoint
The full per-area table for one occupation: every metro and nonmetro area's workers, median annual wage, and location quotient, plus the national figures. Same BLS OEWS data as the local block on the single-career endpoint, all ~530 areas at once. Detailed occupation codes resolve to their OEWS occupation (combined-occupation alias or SOC broad group where needed); aggregate SOC levels and military occupations return 404 GEO_NOT_AVAILABLE. Suppressed BLS values are null, never zero.
Query Parameters
All parameters are optional.
| Parameter | Type | Description |
|---|---|---|
| type | string | Filter to metro or nonmetro areas |
| state | string | Filter to one state by two-letter abbreviation, e.g. MA |
| sort | string | lq (default), workers, or medianWage. Always descending, suppressed values last |
Example Response
GET /ext/api/career/15-1252.00/local?state=MA&sort=workers
{
"success": true,
"data": {
"code": "15-1252.00",
"occCode": "15-1252",
"title": "Software Developers",
"national": { "workers": 1687890, "medianWage": 135980 },
"areaCount": 5,
"areas": [
{
"code": "14460",
"title": "Boston-Cambridge-Newton, MA-NH",
"state": "MA",
"type": "metro",
"workers": 42310,
"medianWage": 166090,
"locationQuotient": 1.44
},
{
"code": "49340",
"title": "Worcester, MA-CT",
"state": "MA",
"type": "metro",
"workers": 4160,
"medianWage": 139560,
"locationQuotient": 0.71
}
],
"vintage": "May 2025 OEWS"
}
}Area Search Endpoint
Area discovery: how a consumer goes from a place name like "boston" to the area ID the career endpoints take as ?area=. With no parameters it returns the full directory of ~530 OEWS areas. The list changes once a year with the OEWS release, so responses cache hard.
Query Parameters
All parameters are optional.
| Parameter | Type | Description |
|---|---|---|
| q | string | Name search over ~32k US places and the area titles themselves, ranked the same way the site's location dropdown ranks them. Supports "name" or "name, ST" (e.g. boston, ma). Each hit includes matchedPlace showing which place matched |
| county | string | Resolve a 5-digit county GEOID to its one containing area. Mutually exclusive with q |
| type | string | Filter to metro or nonmetro areas |
| state | string | Filter to one state by two-letter abbreviation |
Example Response
GET /ext/api/geo/areas?q=boston, ma
{
"success": true,
"data": {
"areas": [
{
"code": "14460",
"title": "Boston-Cambridge-Newton, MA-NH",
"state": "MA",
"type": "metro",
"matchedPlace": "Boston, MA"
}
],
"count": 1,
"vintage": "May 2025 OEWS"
}
}Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | INVALID_SOC_CODE | SOC code doesn't match expected format |
| 400 | INVALID_LEVEL | Bulk endpoint: level must be one of major, minor, broad, detailed |
| 400 | INVALID_LABEL | Bulk endpoint: label must be one of the 6 resilience labels |
| 400 | INVALID_PAGE | Bulk endpoint: page must be a positive integer (1-indexed) |
| 400 | INVALID_PAGE_SIZE | Bulk endpoint: pageSize must be between 1 and 500 |
| 400 | INVALID_QUERY | Search endpoint: q is required and must be at least 2 characters |
| 400 | INVALID_LIMIT | Search endpoint: limit must be between 1 and 200 |
| 400 | INVALID_BAND | Bad band value — expected entry, mid, or senior |
| 400 | INVALID_AREA | Unknown OEWS area ID — list valid IDs via the Area Search Endpoint |
| 400 | AMBIGUOUS_LOCATION | Mutually exclusive location params passed together (area + county, or q + county) |
| 400 | INVALID_TYPE | Bad type value — expected metro or nonmetro |
| 400 | INVALID_SORT | Bad sort value — expected lq, workers, or medianWage |
| 404 | CAREER_NOT_FOUND | No career exists for the given SOC code |
| 404 | COUNTY_NOT_FOUND | No OEWS area for the given county GEOID |
| 404 | GEO_NOT_AVAILABLE | OEWS does not publish area data for the occupation (aggregate SOC levels, military) |
| 429 | RATE_LIMITED | Exceeded 100 requests/minute. Includes Retry-After header. |
Rate Limiting
The API is rate limited to 100 requests per minute per IP address using a sliding window. If you hit the limit, you'll receive a 429 response with a Retry-After header indicating how many seconds to wait.
CORS
This API supports cross-origin requests from any domain. You can call it directly from browser-based applications without a proxy.
MCP Server for AI Assistants
We provide a Model Context Protocol (MCP) server that wraps this API, allowing AI assistants like Claude to look up career resilience data directly. No API key required.
Install via npm: ai-resilience-mcp
Configuration
Add the following to your MCP client configuration:
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"ai-resilience": {
"command": "npx",
"args": ["-y", "ai-resilience-mcp"]
}
}
}Claude Code
Add to your project's .mcp.json:
{
"mcpServers": {
"ai-resilience": {
"command": "npx",
"args": ["-y", "ai-resilience-mcp"]
}
}
}Available Tools
| Tool | Input | Description |
|---|---|---|
| lookup_career | code (SOC code); optional area, county, band | Returns the career payload: AI resilience score, label, confidence, explanation, AIRM data (airm_cv), the experience outlook, and — with an area or county — the local wage/employment picture |
| search_areas | q (place name) | Finds the OEWS area ID for a place name ("boston" → Boston-Cambridge-Newton, MA-NH), for use as area in the other tools |
| lookup_local | code; optional type, state, sort, limit | Full per-area wage and employment table for one occupation (workers, median wage, location quotient by metro/nonmetro area) |
Changelog
Notable changes to the API. Breaking changes are called out explicitly.
2026-09-16
API v2.1The geo ("Local Picture") and expertise ("Experience Outlook") layers. Everything is additive on top of v2.0 — no existing field changed — so this bumps the minor per the policy below.
- Single-career endpoint: new
?area=and?county=params add adata.localblock (workers, median wage, location quotient, national comparison) for one metro or nonmetro area. - Added
GET /ext/api/career/{code}/local— the full per-area table for one occupation, withtype,state, andsortfilters. - Added
GET /ext/api/geo/areas— area directory, name search (?q=), and county-GEOID resolution (?county=). - Task rows on the single-career and tasks endpoints gain
expertiseLevel. - Single-career endpoint: new
data.expertiseblock (ΔExpertise score and percentile, routine vs expert resilience and erosion, ten-year wage/employment forecast with bounds and out-of-sample caveat, per-band outlooks). Optional?band=entry|mid|seniornarrows the bands map. - Added the geo dataset CSV:
GET /ext/api/dataset-geo.csv(one row per occupation per area; the maindataset.csvis unchanged). X-API-Versionis now also sent by the dataset routes, which had been missing it despite the 2026-05-26 note saying it is on all responses.- The
attributionobject gains asourcesarray crediting BLS OEWS (May 2025) and Autor & Thompson (2025). - New error codes:
INVALID_BAND,INVALID_AREA,AMBIGUOUS_LOCATION,COUNTY_NOT_FOUND,INVALID_TYPE,INVALID_SORT,GEO_NOT_AVAILABLE.
2026-08-25
field renamesv2.0Breaking: several response fields were renamed so the name says which source or subscore the value belongs to. Values are unchanged; only the keys moved. Update any client reading the old names.
data.airm→data.airm_cv(all child fields unchanged)data.sources.blsOpportunity→data.sources.lted_blsOpportunitydata.sources.wrtmj.riskPercent→data.sources.wrtmj.rawRiskPercentdata.sources.manning.rawScore→data.sources.manning.adaptiveCapacityRawScoredata.laborMarket.employmentChangePct→data.laborMarket.employmentChangePctBLSdata.laborMarket.annualOpenings→data.laborMarket.annualOpeningsBLS- Fixed
data.airm_cv.version, which reported "v0.1"; it now correctly reports the model version, "v1.5". - Dataset CSV: removed the
bls_percentileandbls_opportunityScorecolumns. Both duplicatedltedScore, which remains.
2026-08-21
raw scores + confidence scorev1.5The single-career endpoint now exposes every field in the downloadable dataset CSV. Additive and backward compatible. Also corrects X-API-Version, which had stayed at 1.0 through the four additive releases above; it now reports 1.5 and earlier entries carry the version they should have shipped with.
- Added
data.aiResilience.confidenceScore— the 0-100 numeric score behind the existingconfidencelevel. - Added
data.sources.althoff.rawScoreanddata.sources.manning.rawScorealongside their existing percentiles. Null where the source does not cover the career.
2026-08-03
openai signalsv1.4Added the OpenAI Signals AI-exposure source. Additive and backward compatible. (Logged retroactively.)
- Added
data.sources.openaiwithpercentileandrawScore. Both null where the source does not cover the career. - Added
openai_percentileandopenai_rawcolumns to the dataset CSV download.
2026-07-30
attribution objectv1.3Every successful response now includes a top-level attribution object carrying the CC BY 4.0 credit text, canonical URL, and license link. Additive and backward compatible: no existing field changed, so clients reading data or meta are unaffected.
2026-06-22
report endpointv1.2Added the narrative career-report endpoint.
- Added
GET /ext/api/career/{code}/report. Returns the written career report as an orderedcareerReportarray of{ type, title, content }sections. - Section types:
Summary,resilienceParagraph(analysis Q&A),replacementVerdict, andsuggestedActions. Content is markdown-formatted text.
2026-06-09
search + tasks endpointsv1.1Two new endpoints plus internal usage analytics.
- Added
GET /ext/api/careers/search?q=. Title/keyword search. Supportslimit(default 50, max 200) andlevelfilter. Returns the same summary shape as the bulk endpoint. - Added
GET /ext/api/career/{code}/tasks. Tasks-only view of an occupation, smaller payload than the full single-career endpoint. - New 400 error codes:
INVALID_QUERY,INVALID_LIMIT. - Internal: per-endpoint usage counters now tracked in Upstash Redis. MCP traffic is bucketed separately via the
User-Agentheader (ai-resilience-mcp). No user-visible change.
2026-05-26
bulk endpointv1.0Added a new bulk (list) endpoint: GET /ext/api/careers. Returns summary entries (code, name, slug, level, url, resilience score/label/confidence) for all occupations.
- Optional filters:
?level=and?label=. - Optional pagination:
?page=N&pageSize=N(default 100, max 500). When neither is supplied, returns the full unpaginated list. - New 400 error codes:
INVALID_LEVEL,INVALID_LABEL,INVALID_PAGE,INVALID_PAGE_SIZE.
2026-05-26
API v1.0Formally declared the REST API contract version as v1.0. This is distinct from the AI Resilience Model version (data.airm.version), which remains at v1.5.
- Added an
X-API-Versionresponse header on all responses so clients can detect the contract version without parsing the body. - Breaking changes to the REST contract will bump the major version (v2.0, v3.0, etc.); additive changes will bump the minor.
2026-05-26
expanded responseSignificantly expanded the response with additional data exposed from the site. All previously-existing fields are unchanged.
- Added
data.sourceswith per-source signals (Anthropic, Microsoft, WRTMJ, Althoff, Manning, BLS opportunity). - Added
data.subscores(meaningful human contribution, sustained economic opportunity). - Added
data.stepsToTake— AI-generated suggested actions for students. - Added
data.taskswith task-level automation likelihood / resilience scores (detailed occupations only). - Added
data.laborMarketwith BLS employment, wage, education, and experience data. - Added
data.hierarchy(parents, siblings, children) for navigating the SOC tree. - Added
data.lastUpdated,data.nameShort,data.slug,data.level, anddata.description.
2026-05-26
model v1.5 (airm)- Breaking: Renamed
data.cvModeltodata.airmin the response. - Added
data.airm.versionfield reporting the AI Resilience Model version.
Questions? Contact us at air@careervillage.org.
Share your feedback