← Dashboard|API Reference
v1.1.0TY2025

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

StatusCodeReason
401UNAUTHORIZEDNo credentials provided
401INVALID_API_KEYAPI key not found, expired, or inactive
401INVALID_TOKENBearer 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
}
HTTPCodeDescription
400VALIDATION_ERRORRequest body or params failed schema validation
400INVALID_TAX_YEARtaxYear parameter is not a valid integer
400UNSUPPORTED_TAX_YEARtaxYear not in the supported years list
401UNAUTHORIZEDNo authentication credentials provided
401INVALID_API_KEYAPI key invalid, expired, or revoked
401INVALID_TOKENBearer token invalid or expired
403FORBIDDENToken lacks the required scope
404SESSION_NOT_FOUNDSession ID does not exist for this user
500SCHEMA_ERRORInternal error building the fact schema
500CREATE_SESSION_ERRORInternal error creating a session
500LIST_SESSIONS_ERRORInternal error listing sessions
500GET_SESSION_ERRORInternal error fetching session
500DELETE_SESSION_ERRORInternal error deleting session
500SET_FACTS_ERRORInternal error writing facts to engine
500GET_FACTS_ERRORInternal error reading facts from engine
500CALCULATE_ERRORInternal error during tax computation
500EXPLAIN_ERRORInternal error building explanation tree
500VALIDATE_ERRORInternal error during validation

Health Check

GET/api/healthPublic — no auth required

Returns 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

GET/api/tax/schema

Returns 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

NameTypeDescription
taxYearintegerTax year to build the schema for. Defaults to the current year.
filterstringCase-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

POST/api/tax/sessions

Creates 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

NameTypeDescription
taxYear*integerTax year (2024–2026).
filingStatusstringOptional 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

GET/api/tax/sessions

Returns 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

GET/api/tax/sessions/:sessionId

Returns the full session record including metadata. The serialized engine state (stateJson) is not returned in this response.

Path Parameters

NameTypeDescription
sessionId*stringThe 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

DELETE/api/tax/sessions/:sessionId

Permanently deletes a session and its stored engine state. This action cannot be undone.

Path Parameters

NameTypeDescription
sessionId*stringThe session ID to delete.

Response

{ "deleted": true }

Set Facts

POST/api/tax/sessions/:sessionId/facts

Writes 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

NameTypeDescription
sessionId*stringTarget session ID.

Request Body

NameTypeDescription
facts*objectMap 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

PUT/api/tax/sessions/:sessionId/facts

Reads 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

NameTypeDescription
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

POST/api/tax/sessions/:sessionId/calculate

The 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

NameTypeDescription
factsobjectOptional map of fact path → string value to set before computing.
outputPathsstring[]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

POST/api/tax/sessions/:sessionId/explain

Returns 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

NameTypeDescription
path*stringThe 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

GET/api/tax/sessions/:sessionId/validate

Validates 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-return
concurrency: 10retries: 2
Event:tax/compute.requested

Hydrates 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-return
retries: 1
Event:tax/validate.requested

Loads 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-returns
concurrency: 5retries: 1
Event:tax/batch-compute.requested

Triggers 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 NameDescription
create_tax_sessionStart a new tax return session
set_tax_factsSet taxpayer input values on a session
get_tax_factsRead computed or input fact values
calculate_taxRun full tax computation engine
explain_tax_calculationShow computation tree for a derived value
validate_tax_returnCheck for validation errors and constraint violations
search_tax_schemaDiscover available fact paths by keyword
list_tax_sessionsList all existing tax sessions