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. 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. 2. POST the transaction. One request carries the property, the parties, the transfer tax declaration, and the recording block.
  3. 3. Download the PDF. The response includes an authenticated PDF URL and a public verification URL.
Create a deed
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"
      }
    }
  }'
Response
{
  "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_ and dp_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-Limit and X-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_typeInstrumentgrantee.vestingAlso required
grant_deedGrant Deedrequired
quitclaim_deedQuitclaim Deed
A quitclaim conveys whatever interest the grantor holds, so vesting is optional.
optional
interspousal_transferInterspousal Transfer Deedrequired
warranty_deedWarranty Deedrequired
tax_deedTax Deedrequired
grant_deed_jtGrant 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_rosGrant 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_corpGrant Deed — Corporate Grantor
The deed recites the state under whose laws the corporation is organized.
required
grantor.entity.entity_state
grant_deed_partnershipGrant Deed — Partnership Grantor
The deed recites the partnership type and the state under whose laws it is organized.
required
grantor.entity.entity_state
grantor.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-48219

Keys 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"
  }
}
StatusCodeWhat it means
401UNAUTHORIZEDMissing, malformed, or unrecognized key.
403FORBIDDENThe key exists but has been deactivated.
404NOT_FOUNDNo deed with that id belongs to your key. Deeds are scoped per key.
422validationA 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.
429RATE_LIMITEDHourly or daily ceiling reached. Check the rate-limit headers.
500INTERNAL_ERRORSomething 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.

2026-08 · v1 — Nine deed types (grant, quitclaim, interspousal, warranty, tax, joint tenancy, community property with right of survivorship, corporate and partnership grantors). Idempotency keys. Per-key rate limits and usage reporting. Public document verification.

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.