Overview
The IntelliCore Tax Engine is a REST API that wraps the IRS Direct File FactGraph engine. It lets you create tax sessions, set taxpayer input facts, run computations, and retrieve derived values — all scoped per user and persisted in PostgreSQL.
- Base URL
- https://your-domain.com
- Tax Year
- 2025 (default)
- Content-Type
- application/json
- Framework
- Next.js 16 App Router
Quick Start
# 1. Create a session
curl -X POST https://your-domain.com/api/tax/sessions \
-H "x-api-key: tke_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "taxYear": 2025, "filingStatus": "single" }'
# 2. Set taxpayer facts
curl -X POST https://your-domain.com/api/tax/sessions/{sessionId}/facts \
-H "x-api-key: tke_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"facts": {
"/formW2/wages": "75000",
"/filingStatus": "single"
}
}'
# 3. Compute the return
curl -X POST https://your-domain.com/api/tax/sessions/{sessionId}/calculate \
-H "x-api-key: tke_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"outputPaths": [
"/refundOrBalanceDue",
"/totalTax",
"/adjustedGrossIncome"
]
}'Authentication
All endpoints (except /api/health) require authentication. The engine supports API key auth plus a service token for Inngest.
API Key (recommended)
Pass a tke_-prefixed key in the x-api-key header. Keys are stored as SHA-256 hashes and never in plain text. Each key has a name, optional expiry, and a set of scopes.
# Using x-api-key header curl -H "x-api-key: tke_your_api_key" ... # Alternatively, as a Bearer token curl -H "Authorization: Bearer tke_your_api_key" ...
Inngest Service Token
A static secret set via the INNGEST_SERVICE_TOKEN environment variable. Used by Inngest workflow callbacks. Grants read, write, compute scopes. The comparison is constant-time to prevent timing attacks.
curl -H "Authorization: Bearer <INNGEST_SERVICE_TOKEN>" ...
Auth Error Responses
| Status | Code | Reason |
|---|---|---|
| 401 | UNAUTHORIZED | No credentials provided |
| 401 | INVALID_API_KEY | API key not found, expired, or inactive |
| 401 | INVALID_TOKEN | Bearer token is invalid or expired |
Accessing from Another Vercel Project
To call this API from a separate Vercel deployment (e.g. app.fastmax.co), follow these steps.
Step 1 — Generate an API key
Insert a hashed key directly into the api_keys table. Generate a secure random token, SHA-256 hash it, and store the hash.
# 1. Generate a random token (keep this secret — store it in your calling app)
node -e "const c=require('crypto');const k='tke_'+c.randomBytes(32).toString('hex');console.log('TOKEN:',k);const h=c.createHash('sha256').update(k).digest('hex');console.log('HASH:',h);"
# 2. Insert the hash into the database (run in your Neon/Postgres console)
INSERT INTO api_keys (name, key_hash, scopes, is_active)
VALUES ('fastmax-app', '<HASH_from_above>', ARRAY['read','write','compute'], true);Step 2 — Add environment variables to the calling Vercel project
In the Vercel dashboard for app.fastmax.co, go to Settings → Environment Variables and add:
TAX_ENGINE_API_KEY=tke_<your_token_from_step_1> TAX_ENGINE_BASE_URL=https://<this-project>.vercel.app
Step 3 — Allow CORS from your domain
In this project's Vercel dashboard, add the ALLOWED_ORIGINS environment variable so the middleware permits cross-origin requests:
ALLOWED_ORIGINS=https://app.fastmax.co
Multiple origins are comma-separated. Use * for unrestricted access (not recommended in production).
Step 4 — Call the API from your Next.js app
Use the token from Step 1 in every request. Server-side calls (Route Handlers, Server Actions) use the x-api-key header. Never expose the token to the browser.
// lib/taxEngine.ts (server-only helper)
const BASE_URL = process.env.TAX_ENGINE_BASE_URL!;
const API_KEY = process.env.TAX_ENGINE_API_KEY!;
export async function taxFetch(path: string, init?: RequestInit) {
const res = await fetch(`${BASE_URL}${path}`, {
...init,
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY,
...init?.headers,
},
});
if (!res.ok) throw new Error(`Tax API ${res.status}: ${await res.text()}`);
return res.json();
}
// Example — create a session
const session = await taxFetch("/api/tax/sessions", {
method: "POST",
body: JSON.stringify({ taxYear: 2025, filingStatus: "single" }),
});Error Codes
All error responses share the same envelope:
{
"error": "Human-readable message",
"code": "MACHINE_READABLE_CODE",
"details": { ... } // optional validation details
}| HTTP | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Request body or params failed schema validation |
| 400 | INVALID_TAX_YEAR | taxYear parameter is not a valid integer |
| 400 | UNSUPPORTED_TAX_YEAR | taxYear not in the supported years list |
| 401 | UNAUTHORIZED | No authentication credentials provided |
| 401 | INVALID_API_KEY | API key invalid, expired, or revoked |
| 401 | INVALID_TOKEN | Bearer token invalid or expired |
| 403 | FORBIDDEN | Token lacks the required scope |
| 404 | SESSION_NOT_FOUND | Session ID does not exist for this user |
| 500 | SCHEMA_ERROR | Internal error building the fact schema |
| 500 | CREATE_SESSION_ERROR | Internal error creating a session |
| 500 | LIST_SESSIONS_ERROR | Internal error listing sessions |
| 500 | GET_SESSION_ERROR | Internal error fetching session |
| 500 | DELETE_SESSION_ERROR | Internal error deleting session |
| 500 | SET_FACTS_ERROR | Internal error writing facts to engine |
| 500 | GET_FACTS_ERROR | Internal error reading facts from engine |
| 500 | CALCULATE_ERROR | Internal error during tax computation |
| 500 | EXPLAIN_ERROR | Internal error building explanation tree |
| 500 | VALIDATE_ERROR | Internal error during validation |
Health Check
/api/healthPublic — no auth requiredReturns the health status of the database and the FactGraph engine. Returns 200 when both checks are healthy, 503 otherwise.
Response
{
"status": "healthy" | "degraded",
"timestamp": "2025-04-01T00:00:00.000Z",
"checks": {
"database": {
"status": "healthy" | "unhealthy",
"latencyMs": 4,
"error": "..." // only present on failure
},
"engine": {
"status": "healthy" | "degraded" | "unhealthy",
"latencyMs": 120,
"taxYear": 2025,
"available": [2024, 2025],
"error": "..." // only present on failure
}
}
}Tax Schema
/api/tax/schemaReturns all fact paths available in the tax dictionary for a given year. Use this endpoint to discover the names you can pass to /facts and /calculate.
Query Parameters
| Name | Type | Description |
|---|---|---|
| taxYear | integer | Tax year to build the schema for. Defaults to the current year. |
| filter | string | Case-insensitive substring filter applied to the path list. |
Response
{
"taxYear": 2025,
"taxYearInfo": {
"taxYear": 2025,
"available": [2024, 2025]
},
"totalPaths": 1842,
"filteredPaths": 12,
"paths": [
"/filingStatus",
"/formW2/wages",
"/adjustedGrossIncome",
...
]
}Example
curl "https://your-domain.com/api/tax/schema?filter=wages&taxYear=2025" \ -H "x-api-key: tke_your_api_key"
Create Session
/api/tax/sessionsCreates a new tax session for the authenticated user. A session holds the serialized FactGraph engine state and all intermediate computation results. Returns 201 Created.
Request Body
| Name | Type | Description |
|---|---|---|
| taxYear* | integer | Tax year (2024–2026). |
| filingStatus | string | Optional filing status hint (e.g. 'single', 'mfj'). |
Response — 201
{
"sessionId": "sess_01hzex...",
"taxYear": 2025,
"status": "pending",
"createdAt": "2025-04-01T00:00:00.000Z"
}Example
curl -X POST https://your-domain.com/api/tax/sessions \
-H "x-api-key: tke_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "taxYear": 2025, "filingStatus": "single" }'List Sessions
/api/tax/sessionsReturns all sessions belonging to the authenticated user.
Response
{
"sessions": [
{
"id": "sess_01hzex...",
"taxYear": 2025,
"status": "completed",
"createdAt": "2025-04-01T00:00:00.000Z",
"updatedAt": "2025-04-01T01:00:00.000Z"
}
]
}Get Session
/api/tax/sessions/:sessionIdReturns the full session record including metadata. The serialized engine state (stateJson) is not returned in this response.
Path Parameters
| Name | Type | Description |
|---|---|---|
| sessionId* | string | The session ID returned when the session was created. |
Response
{
"session": {
"id": "sess_01hzex...",
"taxYear": 2025,
"status": "in_progress",
"createdAt": "2025-04-01T00:00:00.000Z",
"updatedAt": "2025-04-01T00:30:00.000Z"
}
}Delete Session
/api/tax/sessions/:sessionIdPermanently deletes a session and its stored engine state. This action cannot be undone.
Path Parameters
| Name | Type | Description |
|---|---|---|
| sessionId* | string | The session ID to delete. |
Response
{ "deleted": true }Set Facts
/api/tax/sessions/:sessionId/factsWrites one or more taxpayer input facts to the session's FactGraph engine, serializes the updated state, and persists it to the database. Fact values are always strings; the engine coerces them to the correct type. Returns a per-fact success/error map.
Path Parameters
| Name | Type | Description |
|---|---|---|
| sessionId* | string | Target session ID. |
Request Body
| Name | Type | Description |
|---|---|---|
| facts* | object | Map of fact path → string value. 1–100 entries. |
Request Example
{
"facts": {
"/filingStatus": "single",
"/formW2/wages": "75000",
"/formW2/federalTaxWH": "12000"
}
}Response
{
"sessionId": "sess_01hzex...",
"results": {
"/filingStatus": { "success": true },
"/formW2/wages": { "success": true },
"/formW2/federalTaxWH": { "success": false, "error": "Path not writable" }
},
"savedPaths": ["/filingStatus", "/formW2/wages"],
"removedPaths": []
}Read Facts
/api/tax/sessions/:sessionId/factsReads specific fact values from the session's engine state. Both writable input facts and computed/derived facts may be queried. Supports up to 200 paths per request.
Note: This uses PUT rather than GET to allow a request body specifying the desired paths.
Request Body
| Name | Type | Description |
|---|---|---|
| paths* | string[] | Array of fact paths to read. 1–200 items. |
Request Example
{
"paths": [
"/filingStatus",
"/adjustedGrossIncome",
"/refundOrBalanceDue"
]
}Response
{
"sessionId": "sess_01hzex...",
"facts": {
"/filingStatus": {
"value": "single",
"stringValue": "single",
"complete": true
},
"/adjustedGrossIncome": {
"value": 75000,
"stringValue": "75000.00",
"complete": true
},
"/refundOrBalanceDue": {
"value": null,
"stringValue": "",
"complete": false
}
}
}Calculate
/api/tax/sessions/:sessionId/calculateThe primary computation endpoint. Optionally sets new facts, then runs the FactGraph engine to produce derived values. If outputPaths is omitted the full string dictionary (all non-empty facts) is returned. Also persists the updated engine state and logs the computation for auditing.
Request Body
| Name | Type | Description |
|---|---|---|
| facts | object | Optional map of fact path → string value to set before computing. |
| outputPaths | string[] | Optional list of paths to return (1–500). Omit for all computed values. |
Request Example
{
"facts": {
"/formW2/wages": "80000"
},
"outputPaths": [
"/adjustedGrossIncome",
"/taxableIncome",
"/totalTax",
"/refundOrBalanceDue"
]
}Response
{
"sessionId": "sess_01hzex...",
"setResults": {
"/formW2/wages": { "success": true }
},
"computedFacts": {
"/adjustedGrossIncome": { "value": 80000, "stringValue": "80000.00", "complete": true },
"/taxableIncome": { "value": 67400, "stringValue": "67400.00", "complete": true },
"/totalTax": { "value": 12564, "stringValue": "12564.00", "complete": true },
"/refundOrBalanceDue": { "value": -564, "stringValue": "-564.00", "complete": true }
},
"validationErrors": [],
"durationMs": 38
}Explain Calculation
/api/tax/sessions/:sessionId/explainReturns the computation tree (dependency graph) that produced the value of a derived fact. Useful for debugging, transparency, and user-facing explanations ("why is my refund this amount?").
Request Body
| Name | Type | Description |
|---|---|---|
| path* | string | The fact path whose computation tree to explain. |
Request Example
{ "path": "/refundOrBalanceDue" }Response
{
"path": "/refundOrBalanceDue",
"currentValue": { "value": -564, "stringValue": "-564.00", "complete": true },
"explanation": {
"path": "/refundOrBalanceDue",
"formula": "totalPayments - totalTax",
"value": "-564.00",
"children": [
{
"path": "/totalPayments",
"formula": "withholding + estimatedPayments",
"value": "12000.00",
"children": [ ... ]
},
{
"path": "/totalTax",
"formula": "incomeTax + selfEmploymentTax",
"value": "12564.00",
"children": [ ... ]
}
]
}
}Validate Return
/api/tax/sessions/:sessionId/validateValidates the current session state against all FactGraph fact limits and constraints. Use this before submitting a return to catch constraint violations.
Response — valid
{
"sessionId": "sess_01hzex...",
"valid": true,
"errors": []
}Response — invalid
{
"sessionId": "sess_01hzex...",
"valid": false,
"errors": [
{
"path": "/formW2/wages",
"message": "Value exceeds allowable maximum"
}
]
}Inngest Functions
Inngest functions are triggered by sending events to the Inngest platform. The webhook handler lives at /api/inngest (GET / POST / PUT are all handled by the Inngest SDK serve helper). Authenticate callbacks with the INNGEST_SERVICE_TOKEN environment variable.
compute-tax-returntax/compute.requestedHydrates the FactGraph engine from the session, sets the provided facts, runs a full computation, and persists the results back to the database.
Event Payload
{
"data": {
"sessionId": "sess_01hzex...",
"facts": {
"/formW2/wages": "75000"
},
"outputPaths": ["/refundOrBalanceDue"]
}
}validate-tax-returntax/validate.requestedLoads the session engine state and validates all facts against FactGraph constraints. Results are stored in the session's computed output.
Event Payload
{
"data": {
"sessionId": "sess_01hzex..."
}
}batch-compute-tax-returnstax/batch-compute.requestedTriggers parallel recomputation for multiple sessions at once. Useful for bulk processing or year-end recomputation after a rule update.
Event Payload
{
"data": {
"sessionIds": ["sess_01hzex...", "sess_02abcd..."]
}
}MCP Server Tools
The MCP (Model Context Protocol) server exposes the tax engine as AI-callable tools. Start the server with pnpm mcp:start. Each tool maps directly to an underlying REST call.
| Tool Name | Description |
|---|---|
create_tax_session | Start a new tax return session |
set_tax_facts | Set taxpayer input values on a session |
get_tax_facts | Read computed or input fact values |
calculate_tax | Run full tax computation engine |
explain_tax_calculation | Show computation tree for a derived value |
validate_tax_return | Check for validation errors and constraint violations |
search_tax_schema | Discover available fact paths by keyword |
list_tax_sessions | List all existing tax sessions |