Sandbox
For building and testing your integration.
$0 forever
No credit card needed.
250 calls a month10 requests a minute
Get a free keySend a price and an address. Get back what the seller nets or what the buyer brings to closing, line by line, with that county's transfer taxes, title customs, recording fees and prorations.
curl https://api.netsheet.org/v1/quote \ -H "Authorization: Bearer $NETSHEET_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "seller", "state": "FL", "county": "Hillsborough", "salePrice": 650000, "firstMortgage": 280000, "commissionRate": 5, "closingDate": "2026-11-16" }'
{
"object": "net_sheet",
"type": "seller",
"headline": { "netProceeds": 322807.87 },
"lines": [
{ "label": "Real estate commission (5%)", "amount": 32500 },
{ "label": "First mortgage payoff", "amount": 280000 },
{ "label": "Documentary stamp tax on deed", "amount": 4550 },
{ "label": "Owner's title insurance policy", "amount": 3325 },
…
]
}
Every plan gets the whole API. You pay for volume: a call is one quote or one address lookup. State, county and rule lookups are free. Pay as you go, take a monthly plan, or both.
Yearly billing costs the same as 10 months.
For building and testing your integration.
$0 forever
No credit card needed.
250 calls a month10 requests a minute
Get a free keyFor a brokerage tool, a CRM add-on or a small site.
$29 a month
5,000 calls a month60 requests a minute. Under 0.6¢ a call.
For lender, title and listing sites with steady traffic.
$99 a month
50,000 calls a month300 requests a minute. Under 0.2¢ a call.
For portals and platforms quoting every listing.
$299 a month
250,000 calls a month1,000 requests a minute. About 0.12¢ a call.
1¢ a call
Buy calls in packs. They never expire, and they are only used once your plan's calls for the month run out, so they work on their own or as a top-up on any plan. Holding calls also raises a Sandbox account to 60 requests a minute.
Plans work out cheaper once you make more than about 2,900 calls a month. You are never billed for calls after the fact: when the plan's calls and your prepaid calls are both used up, the API answers 429 until the 1st, until you buy more, or until you move up a plan (that takes effect at once and is prorated). Need more than 250,000 calls a month? Email support@netsheet.org.
API keys belong to a NetSheet.org account. Create a free account or log in, and you can make a Sandbox key here straight away.
Keep keys on your server. Anyone with a key can spend its calls.
Copy this key now. It is shown once. If you lose it, revoke it and make another.
A JSON API over HTTPS. Base URL: https://api.netsheet.org/v1
Send your key in the Authorization header on every request. X-Api-Key: ns_live_… works too.
Authorization: Bearer ns_live_…
Keys begin with ns_live_. Make and revoke them above. A revoked key stops working at once. Call from your server, not from a web page, where anyone could read the key.
POST /v1/quote 1 call
Calculates a seller net sheet (net proceeds) or a buyer net sheet (cash to close). Nothing is saved. Only type, state and salePrice are required. Give the county too, because many states tax differently by county and city. When you only have an address, call resolve-address first. Anything you leave out is estimated from local custom, and the response lists those estimates under assumptions.
| Field | Type | Meaning |
|---|---|---|
| typerequired | string | seller or buyer |
| staterequired | string | Two-letter code, e.g. FL |
| salePricerequired | number | Sale or purchase price in dollars |
| county | string | County name without the word County, e.g. Hillsborough |
| city, zip | string | Needed where a city has its own transfer tax, as Philadelphia and San Francisco do |
| propertyAddress | string | Echoed back for your records |
| closingDate | string | YYYY-MM-DD. Needed for the property tax proration and the buyer's prepaid interest. Without it, neither is calculated |
| propertyType | string | single-family, condo, townhome, multi-family, land or commercial |
| commissionRate | number | Total commission percent. Default 6 |
| firstMortgage, secondMortgage, helocPayoff | number | Seller loan payoffs |
| annualPropertyTax | number | The actual annual tax bill, when known |
| hoaMonthlyDues | number | Monthly HOA dues |
| sellerCredits, repairs, homeWarranty | number | Seller-paid concessions and costs |
| loanType | string | Buyer financing: conventional, fha, va, usda, jumbo or cash |
| downPaymentPercent, loanAmount | number | Buyer down payment, or the loan amount |
| interestRate | number | Annual percent, for prepaid interest. Default 6.5 |
| earnestMoney | number | Buyer's deposit, credited at closing |
| customFees | array | [{ "name": "Courier", "amount": 75, "payer": "seller" }] |
Money accepts numbers or strings such as "$150,000". The response has the headline figure (netProceeds for sellers, cashToClose and loanAmount for buyers), the totals for that side, every non-zero line with its group, the assumptions made, any warnings, and the rulesVersion it was calculated with.
const res = await fetch('https://api.netsheet.org/v1/quote', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NETSHEET_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'buyer', state: 'TX', county: 'Travis', salePrice: 400000, loanType: 'conventional', downPaymentPercent: 20, interestRate: 6.5 }) }); const sheet = await res.json(); console.log(sheet.headline); // { cashToClose: …, loanAmount: 320000 }
import os, requests sheet = requests.post( "https://api.netsheet.org/v1/quote", headers={"Authorization": f"Bearer {os.environ['NETSHEET_KEY']}"}, json={"type": "buyer", "state": "TX", "county": "Travis", "salePrice": 400000, "loanType": "conventional", "downPaymentPercent": 20, "interestRate": 6.5}, timeout=30, ).json() print(sheet["headline"])
POST /v1/resolve-address 1 call
Finds the state, county, city and ZIP for a street address, a ZIP code or "City, ST", with that place's closing customs: who customarily pays for the owner's title policy, the usual settlement fee, whether an attorney is required, and the typical property tax rate. Send address, and state or zip when you have them.
curl https://api.netsheet.org/v1/resolve-address \ -H "Authorization: Bearer $NETSHEET_KEY" \ -H "Content-Type: application/json" \ -d '{ "address": "3415 S Virginia Ct, Tampa, FL 33629" }' { "jurisdiction": { "state": "FL", "county": "Hillsborough", "city": "Tampa", "zip": "33629", … }, "customs": { "ownerTitlePolicy": "seller", "attorneyRequired": false, … } }
A place that cannot be found answers 404 and is not counted.
GET /v1/states free
GET /v1/states/{state}/counties free
GET /v1/states/{state}/rules free
The supported states, a state's counties (with FIPS codes and a flag for counties with rules of their own), and a state's rules: each transfer and mortgage tax with its rate, who customarily pays, where it applies, its source and when it was last checked, plus title, recording and county customs. Good for building your own forms and showing your users where a figure came from.
GET /v1/usage free
Your plan, the plan's calls used this month, calls left, when the count resets, and your prepaid credits. The same numbers come back on every metered call in the X-Quota-Limit, X-Quota-Remaining, X-Quota-Reset and X-Credits-Remaining headers.
Each plan has a monthly allowance of calls and a per-minute rate (see Pricing). Once the allowance is used, metered calls come out of your prepaid calls, if you have any. The rate applies to every request, free ones too. Address lookups are also held to 60 a minute on every plan. The count resets at midnight UTC on the 1st of the month. Rate headers follow the IETF RateLimit draft, and a 429 carries Retry-After.
Errors return a status code and a body like { "error": { "type": "invalid_request", "message": "…" } }. The message says what to fix. A request that fails is not counted.
| Type | Status | When |
|---|---|---|
| invalid_request | 400 | A field is missing or cannot be read |
| authentication_required | 401 | No key was sent |
| invalid_key | 401 | The key is wrong or was revoked |
| not_found | 404 | No such endpoint, state or place |
| rate_limited | 429 | Too many requests this minute. Wait for Retry-After |
| quota_exceeded | 429 | This month's plan calls and your prepaid calls are both used up |
| server_error, unavailable | 5xx | Our side. Retry with a short backoff |
Figures are estimates for planning, not a Closing Disclosure. Show your users that title, escrow or the lender confirms the final numbers.
One quote or one address lookup that succeeds. Requests that fail, and lookups of states, counties, rules and your usage, are not counted.
Your prepaid calls are used next, if you have any. When those are gone too, metered requests answer 429 quota_exceeded until the 1st of the month. You are never billed for extra calls after the fact. Buying calls or moving up a plan takes effect at once; a plan change is prorated.
Each rule is taken from the state or county's own statute, fee schedule or rate filing, and records its source and the date it was last checked. You can read them all through /v1/states/{state}/rules. Every quote carries the rulesVersion it used, so you can tell when a figure changed because a rule did.
Yes, that is what the API is for. Present them as estimates, and make the calls from your server so the key stays private.
No. They stay on your account until you use them, including if you cancel a plan. A refunded pack takes back whichever of its calls are still unused.
Open Billing and invoices in your API keys. A cancelled plan runs to the end of the period you paid for, then the account goes back to Sandbox. Your keys keep working on the Sandbox allowance.
No. Professional and Agency are for agents using the app. API plans are billed on their own, and one account can have both.