# Test without spending

import { Card } from "zudoku/ui/Card";
import { Code2, CircleAlert } from "zudoku/icons";

Send `POST /v1/validate` to check your request body without being charged anything.

A call sent from a reference page with your key is a real call; `/v1/validate` is free there too.

## Check the request shape

Use a valid [API key](/definitions), the credential that identifies your [account](/definitions), the record that owns your keys and the money you add.
An account sign-in also works.
This free call works at a zero [balance](/definitions), the money available on your account.

It checks shape, required fields and the property cap for `POST /v1/predict`.
It never calls the underwriting service.

A true result does not prove that the address exists, is inside coverage or can be underwritten.
The underwriting call decides whether a well-formed address can be underwritten.
The [validate reference](/api/scoring#check-a-request-without-spending) describes the accepted body.

In the playground, use plain-text mode with valid JSON and an active `Content-Type: application/json` header.
The request example sets both; other body modes or a missing content type receive `400`.

<CodeTabs syncKey="request-language" hideIcon>

```bash title="cURL"
curl https://api.investorliftdata.com/v1/validate \
  --request POST --max-time 30 \
  --header "Authorization: Bearer $INVESTORLIFT_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"address": "1026 N Beckley Ave, Dallas, TX 75203"}'
```

```javascript title="JavaScript"
const response = await fetch("https://api.investorliftdata.com/v1/validate", {
  method: "POST",
  signal: AbortSignal.timeout(30_000),
  headers: {
    Authorization: `Bearer ${process.env.INVESTORLIFT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ address: "1026 N Beckley Ave, Dallas, TX 75203" }),
});
console.log(await response.json());
```

```python title="Python"
import os
import requests

response = requests.post(
    "https://api.investorliftdata.com/v1/validate",
    headers={
        "Authorization": f"Bearer {os.environ['INVESTORLIFT_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={"address": "1026 N Beckley Ave, Dallas, TX 75203"},
    timeout=30,
)
print(response.json())
```

</CodeTabs>

```json title="Full response" operation="validate"
{
  "valid": true
}
```

## Handle availability

With an API Key it answers even while the Ledger is down.
A connected app reads the Ledger to check that its connection is still approved.
If that lookup is unavailable or its result is unclear, it returns [`503 call-not-started`](/errors/call-not-started).

A revoked connection receives [`401 invalid-key`](/errors/invalid-key).
Nothing is charged either way.

If the operator temporarily switches this endpoint off, it returns [`503 route-unavailable`](/errors/route-unavailable).
Other endpoints are unaffected, and nothing was charged.
Wait for `Retry-After` before sending the same call again.

Any `Idempotency-Key` header is ignored; this free call has no charge to replay.

## Next steps

<div className="docs-next-steps">

<Card className="docs-next-card"><a href="/quickstart"><Code2 className="docs-next-icon" size={18} strokeWidth={1.5} aria-hidden="true" focusable="false" /><strong>Quickstart</strong><span className="docs-next-description">Make your first scored call.</span><span className="docs-next-arrow" aria-hidden="true">→</span></a></Card>

<Card className="docs-next-card"><a href="/production/handle-errors"><CircleAlert className="docs-next-icon" size={18} strokeWidth={1.5} aria-hidden="true" focusable="false" /><strong>Handle errors</strong><span className="docs-next-description">Handle the refusal by its type.</span><span className="docs-next-arrow" aria-hidden="true">→</span></a></Card>

</div>
