Developers / CLI · SDK · REST

Skip trace in
one command.

Turn a US property address into the owner's name, phone numbers with DNC flags, emails, and mailing address. One npm package gives you a CLI and a typed JS/TS SDK; the REST API works from any language. It is the same flat 4¢ per match as the dashboard rate sheet, and misses are always free. For pricing context and how to compare providers, start with the skip tracing API overview.

npm install -g skiptrace
Get an API Key

For AI Agents

Vibe coder?

Copy a ready-made brief with the endpoint, auth, SDK, and error handling, then paste it into your AI coding agent and let it wire up DataSkip for you.

  • Claude
  • Codex
  • Cursor

Everything your agent needs, in one paste.

01 / CLI

The CLI: skip trace from your terminal

Create an API key in the dashboard (Settings → API), save it once, then trace addresses straight from your shell. Exit codes are script-friendly: 0 match, 1 miss, 2 usage error, 3 API error.

$ skiptrace config set-key pc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

$ skiptrace "123 Example St, Phoenix AZ 85001"

$ skiptrace lookup "44 Pine St" --city Bridgewater --state MA --zip 02324

$ skiptrace "123 Main St, Austin TX 78701" --json | jq '.phones'

02 / npm package

The SDK: skip trace from your code

The skiptrace package imports as a typed library. The API key falls back to the SKIPTRACE_API_KEY env var, then the saved CLI config, so new SkipTrace() with no arguments just works. It also ships skipBulk for up to 100 addresses in one call.

skiptrace · node 18+
import { SkipTrace, ApiError } from 'skiptrace';

const st = new SkipTrace({ apiKey: process.env.SKIPTRACE_API_KEY });

try {
  const result = await st.skip('123 Example St, Phoenix AZ 85001');
  if (result.found) {
    console.log(result.contact.fullName, result.phones, result.emails);
  }
} catch (err) {
  if (err instanceof ApiError && err.status === 402) {
    // insufficient balance
  }
}

03 / REST API

The REST API: skip trace from anywhere

One endpoint, any language, with your API key as a Bearer token. A hit charges 4¢ and returns the full contact; a miss returns found: false and charges nothing.

HTTP · Bearer auth

POST https://app.dataskip.io/api/v1/skip-trace

$ curl -X POST https://app.dataskip.io/api/v1/skip-trace \
    -H "Authorization: Bearer pc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "address": "44 Pine St",
      "city": "Bridgewater",
      "state": "MA",
      "zip": "02324"
    }'
{
  "success": true,
  "found": true,
  "charged": 4,
  "contact": {
    "firstName": "J•••",
    "lastName": "C•••••",
    "fullName": "J••• C•••••",
    "propertyAddress": "44 Pine St",
    "propertyCity": "Bridgewater",
    "propertyState": "MA",
    "propertyZip": "02324",
    "mailingAddress": "44 Pine St",
    "mailingCity": "Bridgewater",
    "mailingState": "MA",
    "mailingZip": "02324"
  },
  "phones": [
    { "number": "(•••) •••-0182", "type": "mobile", "dnc": false },
    { "number": "(•••) •••-4415", "type": "landline", "dnc": true }
  ],
  "emails": ["j•••••@•••••.com"]
}
StatusMeaning
200Lookup ran. Check found: a miss is still 200 with contact: null and no charge.
400Missing or invalid address in the JSON body.
401Missing or invalid API key.
402Insufficient balance to cover a match. Top up in the dashboard.
429Rate limited. Retry after the indicated delay.

04 / Bulk API

The bulk API: 100 per request, or a whole CSV

Skip trace up to 100 addresses in one API call, or a whole CSV in one job (never loop the single-lookup endpoint, which is limited to 500 lookups per minute per account). Either way you only pay for hits: misses are refunded automatically, even in bulk. The CSV pipeline handles bigger lists, up to 250,000 records, and previews the matched count and exact cost before anything is charged.

POST https://app.dataskip.io/api/v1/skip-trace-bulk

{
  "addresses": [
    { "address": "123 Sample Ave", "city": "Anytown", "state": "CA", "zip": "90210" },
    { "address": "456 Demo Blvd", "zip": "90211" }
  ]
}
{
  "success": true,
  "total": 2,
  "matched": 1,
  "totalCharged": 4,
  "results": [
    { "found": true, "charged": 4, "contact": { "fullName": "J••• C•••••" }, "phones": ["..."], "emails": ["..."] },
    { "found": false, "charged": 0, "contact": null, "phones": [], "emails": [] }
  ]
}

Up to 100 entries per request; only the address field is required per entry, and results come back in request order with the same shape as a single lookup. Billing matches single lookups: 4¢ per match, misses free. The worst case (every entry matching) is charged up front, a 402 with balanceRequired means the balance cannot cover the batch, and non-matches are refunded automatically when the request completes, so the net charge is always matches only. Rate limit: 250 bulk requests per minute per account, and 429 responses carry a Retry-After header.

await st.skipBulk(['123 Example St, Phoenix AZ 85001', { address: '44 Pine St', city: 'Bridgewater', state: 'MA', zip: '02324' }]);

In the SDK, skipBulk is on the client and as a one-shot export, fully typed (BulkLookupResponse). Free-form strings and structured objects mix in the same array.

For bigger lists, the CSV job pipeline takes one file of up to 250,000 addresses. Jobs created through the API also appear in the dashboard, and skiptrace bulk in the CLI runs this same pipeline.

$ curl -X POST https://app.dataskip.io/api/user/skip-trace \
    -H "Authorization: Bearer pc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "filename": "leads.csv",
      "columnMapping": { "address": "Property Address", "city": "City", "state": "State", "zip": "Zip" }
    }'
  1. Create a job with POST /api/user/skip-trace and your CSV's column mapping (only the address column is required). The response returns a jobId and an uploadUrl.
  2. Upload the raw CSV. Presigned uploads PUT the file to uploadUrl with Content-Type: text/csv and then call the uploaded endpoint; direct uploads POST the file as multipart form data.
  3. Poll the job until its status is preview. The preview reports total rows, matched rows, and the total charge in cents.
  4. Confirm to run the charge, or cancel free of charge. Only matched rows are billed, at 4¢ each; a 402 response means the balance cannot cover the job.
  5. Poll until completed, then fetch the enriched CSV from downloadUrl. Matched rows gain owner names, phones, and emails; unmatched rows come back unchanged.
EndpointWhat it does
POST /api/user/skip-traceCreate a bulk job. Returns jobId and uploadUrl.
POST /api/user/skip-trace/{jobId}/uploadedNotify after a presigned upload finishes.
GET /api/user/skip-trace/{jobId}Job status. Also refreshes an expired downloadUrl on completed jobs.
POST /api/user/skip-trace/{jobId}/confirmConfirm the previewed cost and charge the balance.
POST /api/user/skip-trace/{jobId}/cancelCancel before confirming. No charge.
GET /api/user/skip-traceList the account's 50 most recent jobs.

Job statuses: pending · uploaded · processing · preview · confirmed · generating · completed · failed · cancelled. A job never charges before the preview is confirmed.

Ship it in an
afternoon.

Get Your API Key

4¢ per match · misses free · support@dataskip.io