Skip to main content
The export endpoints let you download your entire filtered dataset as a compressed CSV file — up to 1,000,000 records per export. This is the fastest way to extract large amounts of data from the DealMachine API.

How It Works

  1. You send a request with locations, filters, and optional fields — the same parameters you’d use for a search.
  2. DealMachine builds and runs the query against its BigQuery data warehouse.
  3. The results are written to a compressed CSV file and uploaded to cloud storage.
  4. You receive signed download URLs in the response, which you use to download the file(s).
The entire process happens synchronously in a single API call. No polling or webhooks required.

Available Endpoints

EndpointDescription
Export PropertiesExport properties matching your location and filter criteria
Export PeopleExport people/contacts matching your location and filter criteria
List ExportsList past exports with pagination and status filtering
Get ExportRetrieve a single export by ID to check status or re-download

Important: This Is a Long-Running Request

Unlike most API endpoints that respond in under a second, export requests typically take up to 30 seconds to complete — and can take longer for very large datasets approaching the 1,000,000 record limit. Your HTTP client must be configured to wait for the response. If your client times out before the export completes, you will not receive the download URLs and will need to retry.
Language / ToolConfiguration
cURL--max-time 120
Node.js (fetch)signal: AbortSignal.timeout(120_000)
Python (requests)timeout=120
Go (http.Client)client.Timeout = 120 * time.Second
cURL
curl -X POST "https://api.v2.dealmachine.com/v1/properties/export" \
  -H "Authorization: Bearer dm_sk_live_xxx" \
  -H "Content-Type: application/json" \
  --max-time 120 \
  -d '{ "locations": [{ "type": "state", "code": "TX" }] }'
Python
import requests

response = requests.post(
    "https://api.v2.dealmachine.com/v1/properties/export",
    headers={"Authorization": "Bearer dm_sk_live_xxx"},
    json={
        "locations": [{"type": "state", "code": "TX"}],
        "filters": [
            {"filter_id": "estimated_value", "operator": "range", "value": {"min": 200000, "max": 500000}}
        ]
    },
    timeout=120
)
export = response.json()

for file in export["download_urls"]:
    print(f"Download: {file['url']}")
Node.js
const response = await fetch("https://api.v2.dealmachine.com/v1/properties/export", {
  method: "POST",
  headers: {
    "Authorization": "Bearer dm_sk_live_xxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    locations: [{ type: "state", code: "TX" }],
    filters: [
      { filter_id: "estimated_value", operator: "range", value: { min: 200000, max: 500000 } }
    ],
  }),
  signal: AbortSignal.timeout(120_000),
});

const export = await response.json();
for (const file of export.download_urls) {
  console.log(`Download: ${file.url}`);
}

List And Previous-Export Filters

Exports support the same Query Builder protocol filters as search. You can export only records in specific lists, exclude records in other lists, and skip records your organization has already exported:
{
  "locations": [],
  "include_lists": { "property_list_ids": [123] },
  "exclude_lists": { "property_list_ids": [456] },
  "exclude_previously_exported": true,
  "fields": ["property_full_address", "estimated_value"]
}
Use people_list_ids on people exports. For advanced export exclusion, pass a full exclude_previously_exported object with properties, people, or companies criteria.

Export Limits

LimitValue
Max records per export1,000,000
Max locations per request15
Max filters per request50
If your query matches more than 1,000,000 records, the API returns a 400 error with the actual record count. Narrow your filters or break the export into smaller location-based chunks.
Use the count endpoints (Count Properties or Count People) to check how many records match your filters before running an export. Count requests are free and return instantly.

Credits

Enrichment credits follow the entities included in the export. Property rows and chargeable property fields cost 1 property enrichment credit per unique property. Person, phone, email, and returned contact rows cost 1 people enrichment credit per unique person/contact. Credits are deduplicated within your billing period, so entities you’ve already accessed this month are free. The response includes a credits object showing exactly what was charged:
{
  "credits": {
    "used": 15432,
    "properties": 15432
  }
}
If the export would exceed your plan’s credit allowance, the API returns a 429 error before any data is exported. No credits are consumed in this case. See Credits for more details on how billing works.

Downloading the Files

The download_urls array in the response contains one or more signed URLs. Each URL points to a gzip-compressed CSV file (.csv.gz).
{
  "download_urls": [
    {
      "filename": "properties_export_2026-02-17.csv.gz",
      "url": "https://storage.googleapis.com/...",
      "size": 2457600
    }
  ]
}
Download URLs are signed and time-limited. Download the files promptly after receiving the response. If a URL expires, you’ll need to run the export again.

Opening the Files

The exported CSV files are gzip-compressed. Most modern tools handle this automatically:
ToolHow to open
Python (pandas)pd.read_csv("export.csv.gz") — pandas decompresses automatically
ExcelDecompress first with a tool like 7-Zip, then open the .csv
Google SheetsUpload the .csv.gz file directly — Sheets decompresses it
Command linegunzip export.csv.gz to decompress, then open the .csv

Anchor Types

By default, property exports produce one row per property and people exports produce one row per person. The anchor parameter lets you change what each row represents:
AnchorAvailable OnDescription
propertyPropertiesOne row per property (default for property exports)
personProperties, PeopleOne row per unique person
phoneProperties, PeopleOne row per phone number
emailProperties, PeopleOne row per email address
For example, if a property has two owners, exporting with anchor: "person" produces two rows — one for each owner. Exporting with anchor: "phone" produces one row per phone number across all contacts.

Concurrency

Only one export can run at a time per organization. If you start an export while another is already running, the API returns a 429 error with the code export_in_progress. Wait for the first export to complete before starting another.

Export History

Every export is saved and can be retrieved later using the List Exports and Get Export endpoints. This is useful for:
  • Re-downloading files — if you lose a download URL, you can retrieve it from the export record (as long as the export hasn’t expired).
  • Checking status — see whether a past export completed successfully or failed.
  • Auditing — review what was exported, when, and how many records were included.
Export records include the status (pending, processing, completed, failed), record count, file size, download URLs, and timestamps. Download URLs are time-limited — expired URLs require a new export.

Best Practices

  1. Check the count first. Use the count endpoint to verify the number of matching records before exporting. This is free and helps you avoid hitting the 1,000,000 record limit.
  2. Set generous timeouts. Configure your HTTP client with a timeout of at least 120 seconds. Exports of 500K+ records can take over a minute.
  3. Download immediately. Signed download URLs expire after a limited time. Save the files to disk as soon as you receive the response.
  4. Break large exports into chunks. If you need more than 1,000,000 records, split your request by location (e.g., export one state at a time) or use narrower filters.
  5. Use filters to reduce cost. The more targeted your export, the fewer credits you consume. Add filters to limit results to the records you actually need.