Skip to main content

Data Enrichment API

The Data Enrichment API lets you submit a list of contacts, select which enrichment layers you want to run, and retrieve the enriched rows when the job completes. It is asynchronous: Submit returns a job_id immediately, and your client polls Job Status until ready: true, then calls Result.

EnvironmentBase URL
Productionhttps://backend.ecoreservice.com/api/v1/data-enrichment
Staginghttps://test.ecoreservice.com/backend/api/v1/data-enrichment
Try it in the Playground (staging)

All Data Enrichment endpoints are in the API Playground under Data Enrichment. For now the playground sends these requests to staging only (https://test.ecoreservice.com/backend/api/v1) — use a staging API key.

Not the same as the legacy enrichment endpoints

The legacy /api/v1/enrichment/ routes keep working for existing integrations. New integrations should use /api/v1/data-enrichment/.

Authentication​

All endpoints require your DataCore API key, sent in the Authorization header. Generate and manage keys from the API Connect page in DataCore — see Authentication.

Authorization: Token sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

Authorization: Bearer <key> is also accepted. Requests without a valid key return 401 Unauthorized.

Usage (credit holds, refunds, wallet transactions) is attributed to the account that owns the API key.

Response envelope​

Every endpoint returns the same envelope. Success:

{ "success": true, "data": { ... } }

Error:

{ "success": false, "error": "<error_code>", "detail": "Human-readable message." }

HTTP status codes follow REST conventions (200, 201, 202, 400, 401, 402, 404, 409, 502).

Enrichment layers​

Jobs are priced per selected layer, per row. See Layers for what each layer returns, which combinations are allowed, and current prices.

CodeLabelWhat it returns
L1Career MonitorCurrent employment, title, LinkedIn URL, verified work email, job function/level, contact location.
L2Company LocationCompany HQ address, city/state/country, postal code, HQ phone.
L3New CompanyIf the contact changed jobs: new company name, title, start date, website, work email.
L4New Company LocationHQ address, city/state/country, phone for the new company.
MPAMobile Phone AppendMobile and direct-dial phone numbers.

Layers must be selected in order (L1 → L2 → L3 → L4). MPA can be added to any selection but cannot run alone. Pass "full" to run every active layer in one job.

Only need to know who changed jobs? The standalone Career Monitor API is the simpler option.

Endpoints​

MethodPathPage
GET/layers/Layers
POST/estimate/Estimate
POST/submit/Submit
GET/status/{job_id}/Job Status
GET/result/{job_id}/Result
POST/cancel/{job_id}/Cancel
GET/jobs/List Jobs

End-to-end example​

TOKEN="sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BASE="https://backend.ecoreservice.com/api/v1/data-enrichment"

# 1. Submit
RESP=$(curl -sS -X POST "$BASE/submit/" \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"selected_layers": ["L1", "L2"],
"title": "Q1 renewal list",
"rows": [
{"first_name":"Jane","last_name":"Doe","company_name":"Acme","email":"jane@acme.com"},
{"first_name":"John","last_name":"Smith","company_name":"Globex","email":"john@globex.com"}
]
}')
JOB_ID=$(echo "$RESP" | jq -r '.data.job_id')

# 2. Poll until ready
while : ; do
STATUS=$(curl -sS "$BASE/status/$JOB_ID/" -H "Authorization: Token $TOKEN")
READY=$(echo "$STATUS" | jq -r '.data.ready')
[ "$READY" = "true" ] && break
sleep 15
done

# 3. Fetch result as CSV
curl -sS "$BASE/result/$JOB_ID/?format=csv" \
-H "Authorization: Token $TOKEN" \
-o "enriched.csv"
import time
import requests

TOKEN = "sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BASE = "https://backend.ecoreservice.com/api/v1/data-enrichment"
H = {"Authorization": f"Token {TOKEN}"}

submit = requests.post(f"{BASE}/submit/", headers=H, json={
"selected_layers": ["L1", "L2"],
"title": "Q1 renewal list",
"rows": [
{"first_name": "Jane", "last_name": "Doe", "company_name": "Acme", "email": "jane@acme.com"},
{"first_name": "John", "last_name": "Smith", "company_name": "Globex", "email": "john@globex.com"},
],
}).json()
job_id = submit["data"]["job_id"]

while True:
status = requests.get(f"{BASE}/status/{job_id}/", headers=H).json()["data"]
if status["ready"]:
break
time.sleep(15)

result = requests.get(f"{BASE}/result/{job_id}/", headers=H).json()["data"]
for row in result["results"]:
print(row["enriched_fields"].get("Email"), row["status"])

Credits & billing​

  • Credits are held at submit time based on row_count × sum(per-layer price).
  • When the job finishes, you're billed for successfully enriched rows only. Skipped and failed rows are refunded automatically.
  • Cancelling a running job releases the entire hold.
  • Prices are configurable per account — call GET /layers/ to get your current rate card.

See also Credit Costs.

Limits​

  • Max rows per JSON submission: 10,000. Use multipart CSV for larger lists.
  • Max CSV upload size: 100 MB.
  • Rate limit: 60 requests/minute per API key.

Error codes​

errorHTTPMeaning
validation_error400Request body failed validation.
bad_meta, bad_layers, bad_rows400Submit payload missing a required part.
not_ready409Result requested before the job finished.
insufficient_credits402Your DataCore wallet can't cover the hold.
upstream_insufficient_credits402DataForge rejected the job for credit reasons.
dataforge_error502Transient upstream failure. Safe to retry.
—401Missing or invalid API key.
—404Job id doesn't exist, or doesn't belong to the authenticated account.

Changelog​

DateChange
2026-10-11Initial release of /api/v1/data-enrichment/.