Send a construction pay application — an AIA G702 Application and Certificate for Payment with its G703 Continuation Sheet — or a change order PDF. Get back the figures as JSON, with arithmetic checks. $0.04 per page (up to 25 pages) in USDC per successful read over x402, on Base or Solana. No account, no API key, no subscription. Failed reads are never charged.
There is no reviewer on a paid read, so every response carries the checks a reviewer would make — the G702's own arithmetic, the first-application gross rule, and the retainage-billing rule — plus plain-language warnings when one fails. Verify figures against the document before relying on them.
1. Describe the service (free):
curl https://subpay.ai/api/v1/extract2. Call it with any x402 client. The first request gets 402 Payment Required naming the price and where to pay; the client pays and retries automatically. In TypeScript, with @x402/fetch:
import { readFileSync } from "node:fs";
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
// A wallet holding USDC on Base. It needs no ETH: the facilitator pays gas.
const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const pay = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});
const res = await pay("https://subpay.ai/api/v1/extract", {
method: "POST",
headers: { "Content-Type": "application/pdf" },
body: readFileSync("pay-app.pdf"),
});
console.log(res.status, await res.json());Paying on Solana instead — register the Solana scheme:
import { ExactSvmScheme } from "@x402/svm/exact/client";
import { toClientSvmSigner } from "@x402/svm";
const pay = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [{
network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
client: new ExactSvmScheme(toClientSvmSigner(yourSolanaKeypairSigner)),
}],
});The same service is an MCP server at https://subpay.ai/mcp (Streamable HTTP), for agents that use tools rather than call web APIs. Tools: extract_document (paid, $0.04 per page (up to 25 pages) per successful call, quoted before payment; the PDF base64-encoded in document, optional fileName, subcontractor, gc) and about (free). Payment is per tool call over x402; a call that fails is not charged.
import { createx402MCPClient } from "@x402/mcp";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = createx402MCPClient({
name: "my-agent",
version: "1.0.0",
schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
autoPayment: true,
});
await client.connect(new StreamableHTTPClientTransport(new URL("https://subpay.ai/mcp")));
const result = await client.callTool("extract_document", {
document: readFileSync("pay-app.pdf").toString("base64"),
});POST https://subpay.ai/api/v1/extract with the PDF in any of three forms:
Content-Type: application/pdffiledocument:POST https://subpay.ai/api/v1/extract
Content-Type: application/json
{
"document": "<the PDF, base64-encoded>",
"fileName": "pay-app-27.pdf",
"subcontractor": "Acme Signs LLC",
"gc": "Skanska"
}subcontractor and gc are optional (JSON fields, or query parameters with the other two forms). Naming the parties sharpens telling a subcontractor's request from the GC's change order.
A pay application:
{
"document": {
"documentType": "PAY_APPLICATION",
"applicationNumber": "27",
"periodTo": "2026-06-30",
"grossThisPeriod": 41819.65,
"retainageHeldToDate": 4181.96,
"retainageReleasedThisPeriod": null,
"retainageRatePercent": 10,
"totalCompletedAndStoredToDate": 41819.65,
"contractSumToDate": 63388,
"balanceToFinishIncludingRetainage": 25750.31,
"currentPaymentDue": 37637.69,
"changeOrders": []
},
"checks": [
{ "name": "g702_math", "passed": true,
"detail": "contract sum to date − completed to date (+ retainage held) = balance to finish" },
{ "name": "first_application_gross", "passed": true,
"detail": "first application: gross this period should equal total completed & stored to date" }
],
"warnings": [],
"confidence": 0.95
}A change order:
{
"document": {
"documentType": "CHANGE_ORDER",
"kind": "GC_CHANGE_ORDER",
"issuer": "Balfour Beatty",
"number": "004",
"description": "CE #705 - WTC Garage Scope Gaps - Clearance Bar at 10th Floor Parking Garage",
"amount": 2405.69,
"date": "2025-09-14"
},
"checks": [],
"warnings": [],
"confidence": 0.95
}kind is SUBCONTRACTOR_REQUEST for a request for change order (not yet part of the contract) or GC_CHANGE_ORDER for the general contractor's executed change order. On a retainage billing — no new work, held retainage being paid out — grossThisPeriod is 0 and the payout is in retainageReleasedThisPeriod. Figures not printed on the document are null.
| Network | CAIP-2 id | Asset |
|---|---|---|
| Base | eip155:8453 | USDC 0x8335…2913 |
| Solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | USDC EPjF…Dt1v |
413 and not charged; split them and send the pages you need. 25 pages tops out at $1.00, the default per-payment limit in standard x402 clients.None of these are charged.
| 400 | No PDF in the request, or the wrong field name |
| 402 | Payment required — your x402 client handles this |
| 413 | PDF larger than 4 MB, or more than 25 pages |
| 415 | The body isn't a PDF |
| 422 | Not a pay application or change order (e.g. a lien waiver) — see below |
| 502 | The document couldn't be read |
| 503 | Reading temporarily unavailable |
Documents other than pay applications and change orders — lien waivers, invoices, schedules of values — are refused with 422 and not charged, rather than read wrongly. Tell us what you need and what you'd pay per read, and it shapes what we build next:
POST https://subpay.ai/api/v1/requests
Content-Type: application/json
{
"documentType": "conditional lien waiver",
"fieldsNeeded": "claimant, through date, amount",
"monthlyVolume": 200,
"maxPricePerReadUsd": 0.25
}Free. Over MCP, call request_capability. Please leave out personal information.
Machine-readable: OpenAPI spec and llms.txt.
Use of the API is governed by the API Terms of Use and the Privacy Policy. Questions: support@subpay.ai.