APIUpdated 2026-07-17

API: Bulk Skip-Trace Jobs

Submit up to 10,000 rows as JSON or CSV, poll status, and fetch paginated results.

POST /jobs runs asynchronous skip tracing on up to 10,000 rows per job — the API counterpart of bulk skip tracing in the dashboard. You submit rows, get a job_id back immediately, then either poll for completion or receive a signed webhook. Larger lists remain a dashboard flow.

Three ways to submit rows

All three input modes hit the same endpoint and return the same response.

1. JSON rows

Send a rows array (1–10,000 entries). Each row uses the same fields as POST /trace: address, city, and state required; first_name, last_name, zip, mailing_address/mailing_city/mailing_state/mailing_zip, county, apn, and owner_type optional. Put LLC names in last_name — entity rows bill at your llc_trust_trace rate automatically.

Request (JSON rows)
curl -X POST https://data.acquiredcrm.com/api/v1/jobs \
  -H "Authorization: Bearer ad_live_XXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "my-list",
    "rows": [
      {"first_name":"John","last_name":"Doe","address":"123 Main St","city":"Phoenix","state":"AZ","zip":"85001"},
      {"last_name":"Sunrise Holdings LLC","address":"456 Oak Ave","city":"Portland","state":"OR"}
    ],
    "add_ons": ["dnc"],
    "callback_url": "https://example.com/hooks/acquired-data"
  }'

2. Raw CSV body

Send your export file as-is with Content-Type: text/csv. Column headers are matched case- and punctuation-insensitively ("Property Address" or "Address", "First Name", "Mailing Address", "APN", "Owner Type", and so on), and unrecognized columns are ignored — so Propwire and PropStream exports work unmodified. Columns mapping to address, city, and state are required. Because the body is the file, job options move to query parameters: filename, add_ons (comma-separated), and callback_url (URL-encoded).

Request (CSV body)
curl -X POST "https://data.acquiredcrm.com/api/v1/jobs?filename=my-list&add_ons=dnc,phone_verification&callback_url=https%3A%2F%2Fexample.com%2Fhooks%2Facquired-data" \
  -H "Authorization: Bearer ad_live_XXXX" \
  -H "Content-Type: text/csv" \
  --data-binary @propwire_export.csv

3. Multipart file upload

Put the CSV in a file form field. Options can ride along as form fields (which take precedence) or query parameters, and filenamedefaults to the uploaded file's name.

Request (multipart)
curl -X POST https://data.acquiredcrm.com/api/v1/jobs \
  -H "Authorization: Bearer ad_live_XXXX" \
  -F "file=@propstream_export.csv" \
  -F "add_ons=dnc" \
  -F "callback_url=https://example.com/hooks/acquired-data"

Options and add-ons

  • filename — label for the job and result file.
  • add_ons — any of dnc, phone_verification, litigator, deceased, tested_emails, llc_trust, data_verification, family_contacts. Each is priced per record on top of the trace rate — see GET /pricing and the add-ons guide.
  • callback_url — a public https URL POSTed on completion (no IP literals or local hostnames). See webhooks.

The 202 response

Response
HTTP 202
{
  "job_id": "bc3e1413-9a7d-4a52-b1f0-3c8e5d6f7a89",
  "status": "processing",
  "total_rows": 2,
  "credits_charged": 8,
  "add_ons": ["dnc"],
  "environment": "production"
}

Only one bulk job can run per account at a time — submitting another while one is processing returns 429 job_in_progress with a Retry-After header. Other errors: 402 insufficient_credits when your balance is below the job cost, and 422 validation_error for bad rows, unknown fields, more than 10,000 rows, an unsafe callback_url, or a CSV missing address/city/state columns.

Listing and polling jobs

GET /jobs lists every trace job on the account (dashboard and API), newest first. It takes page (default 1), per_page (default 20, max 100), and an optional source filter (api or app). GET /jobs/{id} returns one job with progress:

Request
curl https://data.acquiredcrm.com/api/v1/jobs/bc3e1413-9a7d-4a52-b1f0-3c8e5d6f7a89 \
  -H "Authorization: Bearer ad_live_XXXX"
Response
{
  "job_id": "bc3e1413-9a7d-4a52-b1f0-3c8e5d6f7a89",
  "status": "complete",
  "progress": { "completed_batches": 1, "total_batches": 1, "percent": 100 },
  "total_rows": 2,
  "credits_charged": 8,
  "filename": "my-list",
  "add_ons": ["dnc"],
  "source": "api",
  "created_at": "2026-07-17T18:00:01Z",
  "completed_at": "2026-07-17T18:02:44Z",
  "error_message": null,
  "download_url": "https://data.acquiredcrm.com/storage/...signed-csv...",
  "results_url": "https://data.acquiredcrm.com/api/v1/jobs/bc3e1413-9a7d-4a52-b1f0-3c8e5d6f7a89/results"
}

When status is complete, download_url is a signed CSV link (valid 1 hour) and results_url serves the rows as JSON.

Fetching results as JSON

GET /jobs/{id}/results paginates with page and per_page (default 100, max 1,000 per page). Rows are flat objects keyed like primary_phone and email_1. Requesting results before the job finishes returns 409 job_not_complete.

Request
curl "https://data.acquiredcrm.com/api/v1/jobs/bc3e1413-9a7d-4a52-b1f0-3c8e5d6f7a89/results?page=1&per_page=100" \
  -H "Authorization: Bearer ad_live_XXXX"
Response
{
  "job_id": "bc3e1413-9a7d-4a52-b1f0-3c8e5d6f7a89",
  "total_rows": 2,
  "page": 1,
  "per_page": 100,
  "rows": [
    {
      "property_address": "123 Main St",
      "property_city": "Phoenix",
      "matched_first_name": "John",
      "matched_last_name": "Doe",
      "primary_phone": "6025551234",
      "email_1": "john@example.com"
    }
  ]
}

Webhook redelivery

If your endpoint missed the completion callback, POST /jobs/{id}/retry-webhook re-delivers it. Pass an optional body of {"callback_url": "https://..."}to set or override the job's destination — this also lets dashboard-created jobs deliver to a webhook after the fact. Details in the webhooks guide.

How billing works

  • Credits are charged upfront for every row when the job is accepted: trace rate per row (base_trace, or llc_trust_trace for entity rows) plus each selected add-on.
  • Rows that don't match are not refunded — you pay per row submitted, not per match.
  • If the job fails, the full charge is refunded automatically.

Need every phone scrubbed against DNC lists? Use DNC jobs, which force the compliance add-ons on.