DeedPro API
Generate recorder-formatted California deeds from your platform. You send the facts of the transaction; the API returns a stored PDF measured to county recorder margins — the same templates and page geometry the DeedPro app itself renders.
Base URL https://deedpro-main-api.onrender.com/api/v1
Quickstart
Three steps from a key to a recordable PDF.
- 1. Get a test key. Request access — three fields, no account needed. We issue keys after a short conversation about what you’re building. Test keys start with
dp_test_. - 2. POST the transaction. One request carries the property, the parties, the transfer tax declaration, and the recording block.
- 3. Download the PDF. The response includes an authenticated PDF URL and a public verification URL.
curl -X POST https://deedpro-main-api.onrender.com/api/v1/deeds \
-H "Authorization: Bearer dp_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-48219" \
-d '{
"deed_type": "grant_deed",
"property": {
"address": "1234 Sycamore Lane",
"city": "Los Angeles",
"state": "CA",
"zip": "90001",
"county": "Los Angeles",
"apn": "5432-001-012",
"legal_description": "LOT 15, BLOCK 3, TRACT 12345, IN THE CITY OF LOS ANGELES..."
},
"grantor": { "name": "JOHN A. DOE AND JANE B. DOE, HUSBAND AND WIFE" },
"grantee": { "name": "ROBERT C. ROE", "vesting": "a single man" },
"transfer_tax": {
"exempt": false,
"value": 750000,
"computed_amount": "825.00",
"basis": "full_value",
"city_tax": true,
"city_name": "Los Angeles"
},
"recording": {
"requested_by": "Pacific Coast Escrow",
"title_order_no": "TO-88231",
"escrow_no": "ESC-44120",
"return_to": {
"name": "ROBERT C. ROE",
"address": "1234 Sycamore Lane",
"city": "Los Angeles",
"state": "CA",
"zip": "90001"
}
}
}'{
"success": true,
"data": {
"deed_id": "deed_8Kd2mQxR4vLp",
"document_id": "DOC-2026-H7K3M",
"deed_type": "grant_deed",
"status": "completed",
"created_at": "2026-08-03T18:22:41Z",
"urls": {
"pdf": ".../api/v1/deeds/deed_8Kd2mQxR4vLp/pdf",
"verification": ".../verify/DOC-2026-H7K3M"
},
"property": { "address": "1234 Sycamore Lane, Los Angeles, CA 90001", ... },
"parties": { "grantor": "JOHN A. DOE AND JANE B. DOE", "grantee": "ROBERT C. ROE" },
"transfer_tax": { "amount": "$825.00", "exempt": false }
}
}Python
import requests
resp = requests.post(
"https://deedpro-main-api.onrender.com/api/v1/deeds",
headers={
"Authorization": f"Bearer {API_KEY}",
"Idempotency-Key": order_id, # safe to retry
},
json=deed_payload,
timeout=60, # PDFs render server-side
)
resp.raise_for_status()
deed = resp.json()["data"]
pdf = requests.get(deed["urls"]["pdf"],
headers={"Authorization": f"Bearer {API_KEY}"})
open(f"{deed['document_id']}.pdf", "wb").write(pdf.content)Node
const res = await fetch("https://deedpro-main-api.onrender.com/api/v1/deeds", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": orderId, // safe to retry
},
body: JSON.stringify(deedPayload),
});
if (!res.ok) {
const { detail } = await res.json();
throw new Error(`${detail.code}: ${detail.message}`);
}
const { data } = await res.json();Authentication
Every request carries your key as a bearer token:
Authorization: Bearer dp_live_...- Test and live keys.
dp_test_anddp_live_. Both generate real PDFs on the same templates; test keys exist so you can build and demo without your traffic mixing into live records. - Shown once. Keys are stored hashed. The full value appears exactly once, when it is created — if it is lost, we issue a new one rather than recovering the old.
- Rate limits. Per-key hourly and daily ceilings. Responses carry
X-RateLimit-LimitandX-RateLimit-Remaining; exceeding one returns 429. Tell us your expected volume and we will set the ceiling to match. - Revocation. A key can be deactivated at any time; calls with it stop immediately and return 403.
Deed types
Nine instruments, each rendered from its own template. The vesting column is worth reading closely: two instruments state their vesting on their own face, and for those the API rejects a supplied value rather than ignoring it.
| deed_type | Instrument | grantee.vesting | Also required |
|---|---|---|---|
grant_deed | Grant Deed | required | — |
quitclaim_deed | Quitclaim Deed A quitclaim conveys whatever interest the grantor holds, so vesting is optional. | optional | — |
interspousal_transfer | Interspousal Transfer Deed | required | — |
warranty_deed | Warranty Deed | required | — |
tax_deed | Tax Deed | required | — |
grant_deed_jt | Grant Deed — Joint Tenancy The instrument states joint tenancy on its face. Send grantee.vesting and the request is rejected — choosing this form is the vesting decision. | fixed by the instrument | — |
grant_deed_cp_ros | Grant Deed — Community Property with Right of Survivorship Vesting is fixed by the instrument. Send grantee.vesting and the request is rejected. | fixed by the instrument | — |
grant_deed_corp | Grant Deed — Corporate Grantor The deed recites the state under whose laws the corporation is organized. | required | grantor.entity.entity_state |
grant_deed_partnership | Grant Deed — Partnership Grantor The deed recites the partnership type and the state under whose laws it is organized. | required | grantor.entity.entity_stategrantor.entity.partnership_type |
What the API will not do
Worth reading before you integrate, and worth handing to your counsel.
It will not decide legal choices for you
Vesting, the transfer-tax basis, whether an exemption applies, which instrument fits the transaction — these arrive as facts you send, and they are recorded as your declarations. DeedPro formats and records; it does not choose. Nothing the API returns is legal advice, and no response asserts that a document is valid, effective, or ready to record.
It will not quietly ignore an input it cannot use
Send a vesting clause to a joint-tenancy deed and you get a 422 naming the conflict — not a 200 and a document that disregarded it. If your input did not shape the instrument, you hear about it.
Some instruments require a human flow by design
v1 covers the deed family only. Affidavits and declarations — Affidavit of Death of Joint Tenant, of Trustee, of Spouse, Homestead Declaration, Certification of Trust, TOD Revocation, Statutory POA — carry execution-act machinery: statements sworn under jurat, initial lines, checkbox elections. Their whole premise is a human hand at the moment of execution, and a machine-to-machine call has no hand. Those instruments stay in the DeedPro app, where a person makes the elections and signs. This is a deliberate boundary, not a gap in the roadmap.
California only
Templates are measured to California county recorder requirements. property.state must be CA.
Idempotency & retries
A deed is a legal instrument, and a retried request must not produce a second one. Send an Idempotency-Key header — your order or file number works well — and a repeat with the same key returns the original deed instead of generating a duplicate.
Idempotency-Key: order-48219Keys are scoped to your API key. PDF rendering happens server-side, so allow a generous timeout (60s) and retry with the same idempotency key rather than a fresh one.
Errors
Errors carry a stable code and a message meant to be actionable.
{
"detail": {
"code": "RATE_LIMITED",
"message": "Hourly rate limit exceeded"
}
}| Status | Code | What it means |
|---|---|---|
| 401 | UNAUTHORIZED | Missing, malformed, or unrecognized key. |
| 403 | FORBIDDEN | The key exists but has been deactivated. |
| 404 | NOT_FOUND | No deed with that id belongs to your key. Deeds are scoped per key. |
| 422 | validation | A required fact is missing, or an input conflicts with the instrument — a vesting clause sent to a fixed-vesting deed, or an entity deed without its organizing state. The message names the field. |
| 429 | RATE_LIMITED | Hourly or daily ceiling reached. Check the rate-limit headers. |
| 500 | INTERNAL_ERROR | Something failed on our side. No deed was stored — retry with the same idempotency key. |
Transfer tax
POST /transfer-tax/calculate returns a county and city breakdown for a value and location. It is a convenience for populating your own declaration — the amount that prints on the deed is the one you send in transfer_tax.
- County rate: $1.10 per $1,000 (R&T §11911).
- City rates apply only to cities that levy their own documentary transfer tax. A city that levies none is reported as levying none — the endpoint does not apply a generic rate.
- City rates are approximations of tiered municipal schedules. Verify against the current schedule for the recording jurisdiction; the response carries this caveat alongside the number.
Versioning & changelog
The current version is v1, covering the deed family. Additive changes — new deed types, new optional fields, new response keys — ship within v1 without notice. A breaking change would ship under a new path (/api/v2), and v1 would keep working; we will not repurpose a field or change what an existing one means underneath you.
Request API access
Three fields, no account needed. Tell us what you’re integrating and we’ll get in touch — we issue keys after a short conversation.
Already have a DeedPro account? Use the full form — it asks a few more questions about volume and timeline.