API Reference
Base URL: https://api.exchek.us
Paid endpoints use the x402 payment protocol (USDC on Base). Session endpoints require a valid jobId from a paid or first-free start.
Endpoints
GET /health
Health check. No payment. Returns { "status": "ok", "service": "exchek-api" }.
POST /api/classify/start-free
First classification free. No payment. Body: { "walletAddress": "0x..." }. Returns jobId, nextStep, and promptForUser on success. If this wallet has already used the free classification, returns 402 with error, promptForUser, nextStep: "payment_required", requiredAction: "pay_start", paymentAmount: "$0.01", and paymentEndpoint: "POST /api/classify/start".
POST /api/classify/start
x402 paid ($0.01). Start a new AITL classification. Returns jobId, nextStep, promptForUser.
POST /api/classify/jurisdiction
x402 paid ($2). Determine jurisdiction (BIS vs ITAR). Body: item fields (description, specifications, intendedUse, notes; optionally performanceParameters, valuation, units, htsCode, scheduleBNumber, endUser, endUse, destinationCountry). Returns jurisdiction, regulatoryAgency, justification, citations, exportRestrictions, licenseRequirements, auditLog.
POST /api/classify/submit-info
No payment. Body: jobId plus item fields (description, specifications, intendedUse, notes; optionally performanceParameters, valuation, units, htsCode, scheduleBNumber, endUser, endUse, destinationCountry). Runs jurisdiction and returns determination; ask user to confirm or refine.
POST /api/classify/submit-classification
No payment. Body: jobId, proposedClassification (regulatoryAgency, eccnOrClassification, justification, exportRestrictions, licenseRequirements, restrictionsJustifications, auditLog). Use when the agent has run classification and submits the result for adjudicator review. Then call request-oor to retrieve the proposal.
POST /api/classify/confirm-jurisdiction
No payment. Body: jobId, confirmed: true or feedback. Confirms or refines jurisdiction.
POST /api/classify/request-oor
No payment. Body: jobId. Runs Order of Review (or returns agent-submitted classification if submit-classification was used); returns proposed ECCN, justification, citations, exportRestrictions, licenseRequirements, auditLog.
POST /api/classify/refine-oor
No payment. Body: jobId, feedback. Refines OOR result.
POST /api/classify/approve
No payment. Body: jobId. Finalizes classification; generates and stores report. Returns reportUrl when Supabase Storage is configured. If report storage fails, returns reportStorageError with a message; the classification is still approved.
POST /api/classify/status
No payment. Body: { "jobId": "..." }. Returns current job state and suggested next step: jobId, state, nextStep, promptForUser, hasItemInfo, hasJurisdiction. Use to recover context (e.g. "where are we?"). Returns 404 if the job is not found.
Error responses
All error responses include error and promptForUser so agents can relay a clear message to the user. Many include nextStep to indicate the suggested next action.
| Code | Meaning |
|---|---|
| 400 | Bad request (e.g. missing jobId, missing confirmed/feedback, invalid proposedClassification). May include validationErrors: [{"field": "...", "message": "..."}]. |
| 402 | Payment required (x402) or first free already used. Response includes nextStep: "payment_required", requiredAction: "pay_start", paymentAmount, paymentEndpoint. |
| 404 | Job not found (session expired or invalid). |
| 500 | Server error (jurisdiction, Order of Review, or refinement failed). Includes promptForUser and nextStep where applicable. |
| 503 | Regulatory data (eCFR) temporarily unavailable. |