Overview
NachoCrunch is an AI-native mortgage pricing platform. The API is organized into three families:
- Public (/api/v1/public/*) — Consumer-facing rate quotes and embeddable widgets. Rate-limited by IP.
- Pricing (/api/v1/pricing/*) — Best-execution pricing, natural-language pricing, bulk pricing. API key required.
- Admin Internal (/api/v1/admin/internal/*) — Operator surface: rate sheets, investors, lock desk, delivery, reports, MI, analytics.
Authentication
API Key (header: X-API-Key)
All pricing and ingestion endpoints require an API key. Issue keys via the admin dashboard or the Keys API.
curl https://app.nachocrunch.com/api/v1/pricing/investors \ -H "X-API-Key: nck_live_XXXXXXXXXXXXXXXX"
Tenant header (optional)
Multi-tenant deployments accept X-Tenant-Id on internal routes. Defaults to the API key's bound tenant.
Rate Limits
| Scope | Limit | Headers |
|---|---|---|
| Public rate quote (per IP) | 10 / minute | 429 on breach |
| Pricing (per API key) | 600 / minute, 60k / day | X-RateLimit-Remaining |
| Bulk pricing (per API key) | 5k scenarios / request | 413 when exceeded |
| Agent chat (per tenant) | 120 / minute | Burst smoothing |
Webhooks
NachoCrunch fires HMAC-signed webhooks for every meaningful state change. Configure
endpoints via POST /api/v1/admin/internal/webhooks.
Signature verification
import hmac, hashlib
def verify(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Event families
sheet.*— rate sheet lifecycle (received, parsed, validated, published)lock.*— lock request lifecycle (submitted, approved, rejected, countered)rate_quote.*— consumer quote created / converteddelivery.*— pool created, loans added, marked deliveredalert.*— rate alerts firing
Key Endpoints
| POST/api/v1/pricing/best-execution | Find best pricing across investors |
| POST/api/v1/pricing/natural | Plain-English pricing query |
| GET/api/v1/pricing/investors | List available investors |
| POST/api/v1/pricing/bulk | Price up to 5k scenarios in one request |
| POST/api/v1/public/rate-quotes | Consumer-facing quote (anonymous) |
| POST/api/v1/admin/internal/agent/chat | Conversational pricing agent |
| POST/api/v1/admin/internal/lock-requests/lock | Submit a lock request |
| POST/api/v1/admin/internal/mi-rate-cards/quote | MI premium quote |
| GET/api/v1/admin/internal/search | Global search |
| GET/api/v1/admin/internal/reports | List operator reports |
| POST/api/v1/admin/internal/delivery/pools | Create a delivery pool |
| POST/api/v1/ingest/upload | Upload a rate sheet for ingestion |
Code Examples
Best-Execution Pricing
curl -X POST https://app.nachocrunch.com/api/v1/pricing/best-execution \
-H "X-API-Key: $NACHOCRUNCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"loan_type": "conventional",
"loan_amount": 500000,
"rate_pct": 6.5,
"lock_days": 30,
"fico_score": 760,
"ltv_pct": 80,
"property_type": "single_family",
"occupancy": "primary",
"loan_purpose": "purchase",
"state": "CA"
}'
import os, httpx
resp = httpx.post(
"https://app.nachocrunch.com/api/v1/pricing/best-execution",
headers={"X-API-Key": os.environ["NACHOCRUNCH_API_KEY"]},
json={
"loan_type": "conventional",
"loan_amount": 500000,
"rate_pct": 6.5,
"lock_days": 30,
"fico_score": 760,
"ltv_pct": 80,
"property_type": "single_family",
"occupancy": "primary",
"loan_purpose": "purchase",
"state": "CA",
},
timeout=30,
)
resp.raise_for_status()
for r in resp.json()["results"][:5]:
print(r["investor_name"], r["net_price"])
const res = await fetch(
"https://app.nachocrunch.com/api/v1/pricing/best-execution",
{
method: "POST",
headers: {
"X-API-Key": process.env.NACHOCRUNCH_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
loan_type: "conventional",
loan_amount: 500000,
rate_pct: 6.5,
lock_days: 30,
fico_score: 760,
ltv_pct: 80,
property_type: "single_family",
occupancy: "primary",
loan_purpose: "purchase",
state: "CA",
}),
}
);
const data = await res.json();
console.log(data.results.slice(0, 5));
Agent Chat
curl -X POST https://app.nachocrunch.com/api/v1/admin/internal/agent/chat \
-H "X-API-Key: $NACHOCRUNCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "Best price on a 760/80/$500k conventional purchase in CA?"}'
Public Rate Quote
import httpx
resp = httpx.post(
"https://app.nachocrunch.com/api/v1/public/rate-quotes",
json={
"scenario": {
"fico": 760, "ltv": 80, "loan_amount": 500000,
"loan_purpose": "purchase", "property_type": "single_family",
"occupancy": "primary", "state": "CA",
},
"borrower_email": "jane@example.com",
"lead_source": "website",
},
)
quote = resp.json()
print("Share link:", f"https://app.nachocrunch.com/q/{quote['quote_token']}")
Versioning
Every response includes the X-API-Version header (currently
0.2.0). Breaking changes ship as new path prefixes
(/api/v2/*); minor additions are backward compatible.
Error Envelope
All errors return a consistent JSON shape:
{
"error": "service_unavailable",
"detail": "A backend service is currently unavailable."
}