Public REST API for Datamoon. Authenticate with an API key issued from your dashboard.
Authentication
Datamoon exposes three groups of endpoints, each with its own auth requirement:
| API group | Auth | How to pass the key |
|---|---|---|
Enrichment (GetDataBy*) and Pixel Results (/v2/results) | Legacy API key | api_key query parameter, form field, or JSON body field |
Audience API — ext (/v2/ext/...) and module (/v2/m/...) | Module API key | X-Api-Key HTTP header |
Topic Search (/v2/b2b-topics/*, /v2/b2c-topics/*) | No auth | — |
Bearer / OAuth tokens are not supported. Every authenticated request must include the appropriate API key.
Base URLs
- Enrichment + Pixel:
https://app.datamoon.com/api/v2 - Audience (ext):
https://app.datamoon.com/api/v2/ext - Audience (module):
https://app.datamoon.com/api/v2/m - Topic Search:
https://app.datamoon.com/api/v2
Audience workflow
Audience creation is asynchronous:
POST /audiences/build— submit filters; returns an audienceidwithstatus: in_progress.GET /audiences/fetch/{id}— poll untilstatus: completed.POST /saved-queries— save the audience as a reusable query (optional).POST /saved-queries/{id}/schedule— configure recurring CSV exports (optional, upsert: re-posting replaces the previous schedule).POST /saved-queries/{id}/runs— trigger a manual run, or wait for the background worker (picks up due schedules within ~1 minute).GET /saved-queries/{id}/runs/{runId}/download— download the run as CSV.POST /audiences/manage/{id}/export— one-shot CSV export (ext is restricted to 13 output fields; module exposes all fields).
Constraints
- Topic limit: at most 5 topic IDs per B2B / B2C audience.
- Event date: must fall within the last 14 days and never in the future.
- Record limit hierarchy: an audience's
record_limit(1–1,000,000; default 1,000,000) is inherited by saved queries unless overridden, and applied to CSV exports. - Monthly usage: each module API key has an independent monthly record budget, set per key. Exceeding it returns
422. Counters reset at the billing cycle; unused records do not roll over. - Field access tiers:
extaudiences expose 13 output fields.moduleaudiences expose the full data dictionary.
Filter object
All audience filters use the same JSON shape:
Code
value_to is only used with the between operator. value is ignored (set to null) for has_value and has_no_value. You can use any field in filter criteria, regardless of whether it appears in the output.
Operators
| Operator | Applies to | Description | Value format |
|---|---|---|---|
= | text, date | Exact match | string or YYYY-MM-DD |
!= | text | Not equal | string |
< | date | Before date | YYYY-MM-DD |
> | date | After date | YYYY-MM-DD |
<= | date | On or before date | YYYY-MM-DD |
>= | date | On or after date | YYYY-MM-DD |
between | date | Inclusive date range | value = start, value_to = end |
in | text, multiselect | Any of the listed values | ["a","b"] |
not_in | text, multiselect | None of the listed values | ["a","b"] |
contains | text | Case-insensitive substring | string |
has_value | text | Field is non-null and non-empty | ignored (use null) |
has_no_value | text | Field is null or empty | ignored (use null) |
Filter field reference
| Field | Label | Type | Operators | Allowed options |
|---|---|---|---|---|
event_date | Event Date | date | =, <, >, <=, >=, between | — |
topic_id | Topic | multiselect | in, not_in | Use /v2/b2b-topics/search or /v2/b2c-topics/search |
score_category | Score Category | multiselect | in, not_in | high, medium, low |
category | Category | text | =, !=, in, not_in | — |
subcategory | Sub Category | text | =, !=, in, not_in | — |
first_name | First Name | text | =, !=, in, not_in, has_value | — |
last_name | Last Name | text | =, !=, in, not_in, has_value | — |
personal_emails | text | =, !=, in, not_in, has_value, contains | — | |
personal_phone | Phone | text | =, !=, in, not_in, has_value | — |
mobile_phone | Mobile | text | =, !=, in, not_in, has_value | — |
personal_state | State | multiselect | in, not_in | US state codes (see below) |
personal_zip | Zip | text | =, !=, in, not_in | — |
gender | Gender | multiselect | in, not_in | m, f, u |
age_range | Age | multiselect | in, not_in | 18-24, 25-34, 35-44, 45-54, 55-64, 65 and older |
married | Married | multiselect | in, not_in | y, n |
children | Children | multiselect | in, not_in | y, n |
income_range | Income | multiselect | in, not_in | less than $20,000, $20,000 - $30,000, $30,000 - $40,000, $40,000 - $50,000, $50,000 - $75,000, $75,000 - $100,000, $100,000 - $150,000, $150,000 - $250,000, $250,000+ |
net_worth | Net Worth | multiselect | in, not_in | -$20,000 to -$2,500, -$2,499 to $4,999, $5,000 to $24,999, $25,000 to $99,999, $100,000 to $249,999, $250,000 to $499,999, $500,000 to $999,999, more than $1,000,000 |
homeowner | Home Owner | multiselect | in, not_in | y, n, p |
job_title | Job Title | text | =, !=, in, not_in, contains | — |
seniority_level | Seniority | multiselect | in, not_in | cxo, director, manager, staff, vp |
department | Department | multiselect | in, not_in | administrative, engineering, executive, finance, marketing, sales, … |
business_email | Business Email | text | =, !=, in, not_in, has_value, contains | — |
company_name | Company | text | =, !=, in, not_in, has_value, contains | — |
company_domain | Company URL | text | =, !=, in, not_in, contains | — |
company_revenue | Company Revenue | multiselect | in, not_in | under 1 million, 1 million to 10 million, 10 million to 50 million, 50 million to 100 million, 100 million to 500 million, 500 million to 1 billion, 1 billion and over |
company_employee_count | Company Size | multiselect | in, not_in | 1 to 10, 11 to 50, 51 to 200, 201 to 500, 501 to 1000, 1001 to 5000, 5001 to 10000, 10000+ |
primary_industry | Industry | text | =, !=, in, not_in, contains | — |
US state codes: ak, al, ar, az, ca, co, ct, de, fl, ga, hi, ia, id, il, in, ks, ky, la, ma, md, me, mi, mn, mo, ms, mt, nc, nd, ne, nh, nj, nm, nv, ny, oh, ok, or, pa, ri, sc, sd, tn, tx, ut, va, vt, wa, wi, wv, wy.
Audience types
The type field on POST /audiences/build determines which filters apply:
| Type | Description | Notes |
|---|---|---|
advanced_search | Universal person search | Topic-only fields (topic_id, category, subcategory, event_date, score_category) are not allowed. |
b2b | B2B intent audience | Requires topic_ids. category, subcategory, company_description are not allowed. |
b2c | B2C intent audience | Requires topic_ids. company_description is not allowed. |
Lifecycle & schedule enums
- Audience status:
in_progress,completed - Run
triggered_by:manual,scheduled - Schedule
interval_unit:day,week,month - Schedule
end_type:never,on_date(requiresend_datein the future)
Restricted output fields (ext only)
The ext tier limits CSV exports and API response records to these 13 fields. Requesting any other field on POST /audiences/manage/{id}/export returns 422 with an allowed_fields array.
| Field | Label |
|---|---|
first_name | First Name |
last_name | Last Name |
personal_emails | |
personal_phone | Phone |
linkedin_url | LinkedIn URL |
personal_address | Address |
personal_address_2 | Address 2 |
personal_city | City |
personal_state | State |
personal_zip | Zip |
personal_zip4 | Zip 4 |
contact_country | Country |
business_email | Business Email |
The module tier returns the full data dictionary.
Error responses
| HTTP | Meaning |
|---|---|
400 | Missing API key (e.g. X-Api-Key header absent). |
403 | Invalid API key, or the feature is not enabled for this account. |
404 | Resource not found, or not owned by this account. |
422 | Validation error — see the errors map. Also returned when an output field is not allowed (allowed_fields array), or when the monthly record limit is exceeded. |
500 | Unexpected server error. |
Validation errors follow the Laravel shape:
Code