Overview
The Andy Partner API lets you check a property for tax-protest savings and then either file the protest yourself or hand the customer to Andy to finish. All requests are JSON over HTTPS and are authenticated with a per-partner API key. Start in sandbox — submissions there are simulated and never filed with a real appraisal district.
| Sandbox | Production | |
|---|---|---|
| Base URL | api-andyv2.andyreach.com | api.theandyapp.com |
| Gateway path | /api/partner-service (address lookup uses /api/property-service) | |
| Real filings? | No — simulated | Yes — filed with the appraisal district |
| Auth header | x-api-key | |
Authentication
Every request must include your secret key in the x-api-key header. Keys are issued per partner and per environment. Treat the key like a password — never embed it in browser or mobile code; call the API from your server.
x-api-key: sk_sandbox_your_key_here
Content-Type: application/jsonThe two flows
Both flows begin the same way — find the address and get an estimate — then diverge at the final step.
- 1 Autocomplete find the address
- 2 Estimate check savings, get estimate_id
- 3 Submit consent + signature → reference_id
- 4 Status track the case
- 1 Autocomplete find the address
- 2 Estimate check savings, get estimate_id
- 3 Handoff send customer details → handoff_id
/api/property-service/real-estate/autocompleteproperty-serviceAddress Autocomplete
Returns matching property addresses for a partial search string. Use it to help a user pick a precise address before requesting an estimate. Optional — you may also pass any full address string straight to /estimate.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
search | string | required | Partial or full address the user has typed (min. 3 characters). |
search_types | string[] | required | Result categories to include. A = address, P = parcel, C = city, G = geo, N = name, T = tract, Z = ZIP. |
curl -X POST 'https://api-andyv2.andyreach.com/api/property-service/real-estate/autocomplete' \
-H 'Content-Type: application/json' \
-H 'x-api-key: sk_sandbox_your_key_here' \
-d '{
"search_types": ["A","P","C","G","N","T","Z"],
"search": "3706 Robinson Ave, Austin"
}'{
"status": "success",
"message": "Property detail retrieved successfully",
"data": {
"input": { "search_types": ["A"], "search": "3706 Robinson Ave, Austin" },
"data": [
{
"address": "3706 Robinson Ave, Austin, TX, 78722",
"city": "Austin",
"zip": "78722",
"county": "Travis County",
"searchType": "A",
"title": "3706 Robinson Ave, Austin, TX, 78722"
}
],
"totalResults": 1,
"returnedResults": 1
}
}/api/partner-service/estimatepartner-serviceGet Savings Estimate
Checks whether a property qualifies for a tax protest and returns the estimated savings and property details. The returned estimate_id is required by both /submit and /handoff.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
address | string | required | Full property address to evaluate, e.g. "3706 Robinson Ave, Austin, TX, 78722". |
curl -X POST 'https://api-andyv2.andyreach.com/api/partner-service/estimate' \
-H 'Content-Type: application/json' \
-H 'x-api-key: sk_sandbox_your_key_here' \
-d '{ "address": "3706 Robinson Ave, Austin, TX, 78722" }'{
"estimate_id": "EST68B8A2CAC6BFC35B",
"eligible": true,
"estimated_savings": 2586.87,
"property": {
"address": "3706 Robinson Ave",
"county": "Travis County",
"assessed_value": 707568.0,
"market_value": 882000.0,
"tax_amount": 14371.51
}
}Note: When a property is not eligible, eligible is false, estimated_savings is 0, and the property value fields are null.
/api/partner-service/submitpartner-serviceSubmit Protest
Files a property tax protest on the owner's behalf. Requires the owner's recorded consent and electronic signature. Returns a reference_id used to track the case with /status.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
estimate_id | string | required | The id returned by /estimate. |
owner | object | required | Owner details: first_name, last_name, email, phone. |
property_type | string | required | "residential" or "commercial". |
consent | object | required | Consent record: accepted (true), timestamp (ISO 8601), ip, version. |
signature | string | required | Owner's electronic signature as a base64 PNG data URI. |
documents | object[] | optional | Optional supporting files: each { url, type } where type is SUPPORTING_DOCUMENT or APPRAISAL. |
source | string | optional | Free-form label identifying your integration, e.g. "partner_app". |
curl -X POST 'https://api-andyv2.andyreach.com/api/partner-service/submit' \
-H 'Content-Type: application/json' \
-H 'x-api-key: sk_sandbox_your_key_here' \
-d '{
"estimate_id": "EST68B8A2CAC6BFC35B",
"owner": {
"first_name": "Jane",
"last_name": "Smith",
"email": "jane.smith@example.com",
"phone": "+15122345678"
},
"property_type": "residential",
"consent": {
"accepted": true,
"timestamp": "2026-08-25T10:00:00.000Z",
"ip": "203.0.113.1",
"version": "v1"
},
"signature": "data:image/png;base64,iVBORw0KGgo...",
"documents": [
{ "url": "https://your-s3-url.com/doc.pdf", "type": "SUPPORTING_DOCUMENT" }
],
"source": "partner_app"
}'{
"reference_id": "REF9A08F1E7FC5DC8",
"status": "SUBMITTED",
"message": "Your protest has been successfully filed"
}/api/partner-service/statuspartner-serviceGet Protest Status
Returns the current status of a previously submitted protest, including the assigned case id once the filing is processed.
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
reference_id | string | required | Query parameter — the id returned by /submit. |
curl 'https://api-andyv2.andyreach.com/api/partner-service/status?reference_id=REF9A08F1E7FC5DC8' \
-H 'x-api-key: sk_sandbox_your_key_here'{
"reference_id": "REF9A08F1E7FC5DC8",
"case_id": "CASEAC8EDE46496EEA9A",
"status": "FILED"
}Note: status progresses through values such as SUBMITTED and FILED as the protest is processed.
/api/partner-service/handoffpartner-serviceHandoff to Andy
Hands the customer off to Andy instead of collecting consent and signature yourself. You send minimal customer details; Andy completes consent, signature, and documents directly with the customer. Returns a handoff_id.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
estimate_id | string | required | The id returned by /estimate. |
customer | object | required | Customer details: first_name, last_name, email (required), phone (optional). |
property_type | string | optional | "residential" or "commercial". |
consent_to_contact | object | required | Consent to be contacted by Andy: accepted (true), timestamp, ip, version. |
source | string | optional | Free-form label identifying your integration. |
curl -X POST 'https://api-andyv2.andyreach.com/api/partner-service/handoff' \
-H 'Content-Type: application/json' \
-H 'x-api-key: sk_sandbox_your_key_here' \
-d '{
"estimate_id": "EST68B8A2CAC6BFC35B",
"customer": {
"first_name": "Jane",
"last_name": "Smith",
"email": "jane.smith@example.com",
"phone": "+15122345678"
},
"property_type": "residential",
"consent_to_contact": {
"accepted": true,
"timestamp": "2026-08-25T10:00:00.000Z",
"ip": "203.0.113.1",
"version": "v1"
},
"source": "partner_app"
}'{
"handoff_id": "HND_MTA3BHAXUVJEYW1A",
"estimate_id": "EST68B8A2CAC6BFC35B",
"status": "HANDOFF_INITIATED",
"expires_at": "2026-09-02T12:48:54.109882Z",
"message": "Customer link generated. Redirect the customer or send via email."
}Errors
Errors return the matching HTTP status and a JSON body of the shape { "code": "…", "message": "…" }. The most common cases:
| HTTP | Code | Meaning |
|---|---|---|
400 | INVALID_INPUT | A required field is missing or malformed. |
401 | INVALID_API_KEY | The x-api-key header is missing, wrong, or revoked. |
404 | NOT_FOUND | The referenced resource (e.g. reference_id) does not exist. |
422 | CONSENT_REQUIRED | consent.accepted / consent_to_contact.accepted was not true. |
429 | RATE_LIMITED | You exceeded the request rate limit for your key. |
5xx | INTERNAL_ERROR | An unexpected server error — safe to retry with backoff. |
code field, a UTC timestamp, and any estimate_id or reference_id involved — never a raw API key.Ready to try it?
Run the whole flow end-to-end against the live sandbox — no real filings are made.