Evictions API
Menu

Quickstart

Sign up, create a test API key in the app, then create, validate and submit a test case against the sandbox and follow it by API and webhooks. About the same calls a production integration will make.

What is available today. Evictions API is a sandbox beta, in test mode only. Available today: sign-up for a free sandbox account, the online case form, the REST API and a sandbox with a fictional test state, where a built-in sandbox reviewer reviews cases automatically, you can step them through to close and receive webhooks. Not available yet: serving notices or filing in court for a real case, in any state, live mode, which would accept real cases and online checkout.

Before you start

Sign-up, the online case form, the REST API and a sandbox work today. Serving notices and filing in court for real cases are not available yet, there is no live mode, and nothing can be bought online, so everything here runs in test mode on a fictional state, and nothing is served or filed.

  • Sign up and create a test key. Anyone can open a sandbox account, with no operator involved. It works in test mode only. Sign up, open “API keys” in the app and create a test key. A test key starts with eak_test_; the examples show it as eak_test_....
  • What a test key can do today. Resolve a jurisdiction, create, validate and submit cases against the sandbox, upload evidence, read cases and their history, and register webhook endpoints to receive events. Test cases use the fictional state ZZ, with sandbox adapters in place of a process server and a court.
  • How sandbox review works. Review in the sandbox is automatic: a built-in sandbox reviewer approves a submitted test case automatically once it enters review, approving the exact documents by their hashes, as a partner attorney will. Nothing moves on without that approval. You can then step the test case through the rest of its life, one step at a time, with advance (step 7), instead of waiting out notice periods and court dates.
  • What it cannot do yet. A live-mode case needs a state that is open (its rules reviewed by a licensed attorney in that state, and a partner attorney confirmed). No state is open yet, so a live-mode case cannot be served or filed. The sandbox reviewer and advance work on test cases only.

Examples use curl and jq. Set your key and the API address once:

Set the API address and your key
export EVICTIONS_API_URL=https://api.evictionsapi.com
export EVICTIONS_API_KEY=eak_test_...

Every request carries the key as Authorization: Bearer. Conventions shared by all endpoints (errors, idempotency, pagination) are in the API reference.

1. Resolve a jurisdiction

Ask whether a state is open for your key’s mode, and what its notice rules are. In test mode, ZZ is the sandbox state.

Resolve the sandbox state
curl "$EVICTIONS_API_URL/v1/jurisdictions/resolve?state=ZZ" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY"
Response (abbreviated)
{
  "served": true,
  "jurisdictionIds": ["us-zz"],
  "action": { "name": "Unlawful Detainer", "court": "Fixture Justice Court" },
  "grounds": {
    "nonpayment": {
      "notice": { "type": "pay_or_quit", "periodDays": 3, "cureRight": true, "serviceMethods": [ ... ] },
      "requiredFacts": ["lease.monthlyRentCents", "ledger", "amountOwedCents"]
    },
    "lease_violation": { ... },
    "holdover": { ... }
  }
}

A state that is not open, or any state with a live key until one opens, answers served: false with no rules:

A state that is not open
{ "served": false, "jurisdictionIds": ["us-ca"], "action": null, "grounds": {} }

2. Create a case

A case starts as a draft. ground is nonpayment, lease_violation or holdover; entryPoint is notice to start at the notice. Dates are YYYY-MM-DD and money is whole cents. The Idempotency-Key header makes the request safe to retry: send the same request with the same key and you get the first response back instead of a second case.

Create a draft case
CASE=$(curl -X POST "$EVICTIONS_API_URL/v1/cases" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "ground": "nonpayment",
  "entryPoint": "notice",
  "property": {
    "line1": "1 Main St",
    "city": "Testville",
    "state": "ZZ",
    "zip": "00000",
    "ownerOfRecord": "Pat Landlord"
  },
  "parties": [
    { "role": "plaintiff", "name": "Pat Landlord" },
    { "role": "defendant", "name": "Terry Tenant" }
  ],
  "lease": { "startDate": "2025-01-01", "monthlyRentCents": 150000 },
  "ledger": [
    { "date": "2026-09-01", "type": "charge", "amountCents": 150000 },
    { "date": "2026-10-01", "type": "charge", "amountCents": 150000 },
    { "date": "2026-10-02", "type": "payment", "amountCents": 50000 }
  ],
  "amountOwedCents": 250000,
  "attestations": {
    "authority": true,
    "notRetaliatory": true,
    "notDiscriminatory": true,
    "servicemember": "no",
    "caresCovered": false
  }
}' | jq -r .id)
echo $CASE
Response, without jq (abbreviated)
{
  "id": "case_21a1f8ed-79f4-4248-a682-10184ca8a5c1",
  "mode": "test",
  "state": "draft",
  "ground": "nonpayment",
  "entryPoint": "notice",
  "data": { ... },
  "deadlines": [],
  "documents": [],
  "nextAction": { "by": "customer", "description": "Complete the case details and submit the case." }
}

Every field is listed under POST /v1/cases. Until the case is submitted you can change it with PATCH /v1/cases/{id}.

3. Upload proof of authority

A case cannot be submitted without a document showing your authority over the property, such as a deed or a management agreement. The file goes in the JSON body as base64, up to 10 MB once decoded. For this walkthrough any small file will do.

Upload evidence
curl -X POST "$EVICTIONS_API_URL/v1/cases/$CASE/documents" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"filename\":\"deed.pdf\",\"purpose\":\"authority\",\"contentBase64\":\"$(printf 'deed' | base64)\"}"
Response
{
  "id": "doc_f31d5d4d-c667-4d2b-ba0f-5dee4893aad3",
  "kind": "evidence",
  "filename": "deed.pdf",
  "contentHash": "df75f3ea1d63370ba642bde84f53668817f063ac887beb86b8593d78cf5642b9",
  "purpose": "authority",
  "createdAt": "2026-10-04T22:15:59.978Z"
}

4. Validate

Validation runs the same checks as submission and changes nothing. Run it as often as you like. Each failed check comes with a reason; before step 3, for example, the authority check fails and says which document is missing.

Validate the case
curl -X POST "$EVICTIONS_API_URL/v1/cases/$CASE/validate" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY"
Response
{
  "results": [
    { "gate": "jurisdiction", "status": "pass" },
    { "gate": "authority", "status": "pass" },
    { "gate": "ground_allowed", "status": "pass" },
    { "gate": "required_facts", "status": "pass" },
    { "gate": "ledger_reconciles", "status": "pass" },
    { "gate": "cares_act", "status": "pass" },
    { "gate": "servicemember", "status": "pass" },
    { "gate": "prohibited_basis", "status": "pass" }
  ],
  "passed": true
}

5. Submit

Submitting a case that passes every check generates its notice and sends the case to attorney review. A case that does not pass is refused with 422 gates_failed, and the check results are in error.details.

Submit the case
curl -X POST "$EVICTIONS_API_URL/v1/cases/$CASE/submit" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY"
Response (abbreviated)
{
  "case": {
    "id": "case_21a1f8ed-79f4-4248-a682-10184ca8a5c1",
    "mode": "test",
    "state": "notice_review",
    "documents": [
      { "kind": "evidence", "filename": "deed.pdf", ... },
      { "kind": "notice", "filename": "case_21a1f8ed-...-notice-nonpayment.pdf", ... }
    ],
    "nextAction": {
      "by": "attorney",
      "description": "The sandbox reviewer is reviewing the notice and approves it automatically. In the sandbox, advance moves it on now."
    }
  },
  "gates": [ ... ]
}

In the sandbox the built-in sandbox reviewer approves the notice automatically, and the sandbox process server then receives it. For a real case, once a state is open, an attorney licensed in the state approves, rejects or asks for changes, and only an approval of the exact documents lets the notice be served.

6. Read status

Every case response carries its state, its deadlines and documents, and a nextAction that says who the case is waiting on. The events list is the history visible to you, oldest first.

Read the case and its events
curl "$EVICTIONS_API_URL/v1/cases/$CASE" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY"

curl "$EVICTIONS_API_URL/v1/cases/$CASE/events" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY"
Events response (abbreviated)
{
  "items": [
    { "action": "submit", "fromState": "draft", "toState": "submitted", ... },
    { "action": "assign_attorney", "fromState": "submitted", "toState": "attorney_assigned", ... },
    { "action": "begin_review", "fromState": "attorney_assigned", "toState": "notice_review", ... },
    { "action": "approve_notice", "fromState": "notice_review", "toState": "notice_approved", "detail": { "sandbox": true }, ... },
    { "action": "send_notice", "fromState": "notice_approved", "toState": "notice_out_for_service", ... }
  ]
}

7. Advance the sandbox case

A real case waits days for service, the notice period and the court. A test case does not have to: each call to advance moves it on by one step and returns the case. The step is whatever the case is waiting for: the sandbox reviewer’s review, the next update from the sandbox process server or court, the end of the notice period (on the case’s own sandbox clock, so other cases are not affected), or the next court outcome, which the sandbox reviewer records. Some steps are a check that finds nothing new yet, so the state stays the same; call again. Repeat until the case is closed.

Move the case on by one step
curl -X POST "$EVICTIONS_API_URL/v1/cases/$CASE/advance" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY"
Response (abbreviated)
{
  "id": "case_21a1f8ed-79f4-4248-a682-10184ca8a5c1",
  "mode": "test",
  "state": "notice_out_for_service",
  ...
  "nextAction": { "by": "platform", "description": "The notice is being served on the tenant." }
}

Every step still follows the rules of a real case: nothing is sent or filed without an approval of the exact documents. A case that is a draft, on hold or finished answers 409 nothing_to_advance, a live-mode case answers 409 sandbox_only, and you can advance at most 60 times a minute.

8. Receive webhooks

Register an https endpoint and the API posts a signed event to it each time a case changes state. Register it before you create or submit a case to receive that case’s events. The signing secret appears in this response only, so store it now.

Register a webhook endpoint
curl -X POST "$EVICTIONS_API_URL/v1/webhook-endpoints" \
  -H "Authorization: Bearer $EVICTIONS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/webhooks/evictions" }'
Response
{ "id": "whe_...", "secret": "whsec_..." }

An endpoint registered with a test key receives events for test cases only. The webhooks guide has the payload, the signature check and the retry schedule.

What next

  • Withdraw a test case with POST /v1/cases/{id}/withdraw, or report that the tenant has paid or cured with POST /v1/cases/{id}/report-cure.
  • List your cases with GET /v1/cases, a page at a time.
  • Read the API reference for every endpoint, field and response.