Micro-batch synchronous match
const url = 'https://dev-api.infiniteaudience.ai/v1/match';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"records":[{"email":"hello@example.com","phone":"example","email_sha256":"example","phone_sha256":"example","full_name":"example","first_name":"example","middle_name":"example","last_name":"example","name_suffix":"example","emails":["hello@example.com"],"emails_sha256":["example"],"phones":["example"],"phones_sha256":["example"],"addresses":[{"address_1":"example","address_2":"example","city":"example","state":"example","zip":"example"}],"address_1":"example","address_2":"example","city":"example","state":"example","zip":"example","dob":"example","iag_person_id":"example"}],"field_list":["example"],"template_id":"example","match_level":["I"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://dev-api.infiniteaudience.ai/v1/match \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "records": [ { "email": "hello@example.com", "phone": "example", "email_sha256": "example", "phone_sha256": "example", "full_name": "example", "first_name": "example", "middle_name": "example", "last_name": "example", "name_suffix": "example", "emails": [ "hello@example.com" ], "emails_sha256": [ "example" ], "phones": [ "example" ], "phones_sha256": [ "example" ], "addresses": [ { "address_1": "example", "address_2": "example", "city": "example", "state": "example", "zip": "example" } ], "address_1": "example", "address_2": "example", "city": "example", "state": "example", "zip": "example", "dob": "example", "iag_person_id": "example" } ], "field_list": [ "example" ], "template_id": "example", "match_level": [ "I" ] }'Synchronous inline matching for small record sets (up to 100 records). Submit your records and the list of attributes you want appended, and receive matched results immediately.
Billing: Usage is emitted per matched record only (unmatched records are free). The platform reserves a conservative ceiling and durably queues finalized usage for billing rather than debiting a local balance field. amount_charged is the conservative USD estimate accepted for provider delivery; it is not a finalized invoice amount.
Records array: one output record per input record — matched or not. Unmatched rows carry match_level/match_type/match_confidence: null and a best-effort iag_person_id derived from the row’s own identity signals (or null if none qualified) — only real matches are billed. Use match_count vs record_count to distinguish real matches from derived-only rows.
For datasets larger than 100 records, use POST /v1/match/file instead. Upload, analysis, and async matching are free until egress. The first successful delivery involving that file-match run emits its one aggregate match usage set together with normal delivery usage.
Retries: pass an Idempotency-Key header to make a retried call safe to repeat without a duplicate charge. The same key with an identical body returns the original response verbatim, at zero additional charge (honored for 24 hours); the same key with a different body is rejected with 409 IDEMPOTENCY_KEY_CONFLICT. Without this header, every call reserves and charges independently — recommended for any integration that may retry on timeout.
Requires ‘purchase’ scope.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Optional. Makes a retried call safe to repeat — see the endpoint description’s Retries section.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Records to match (max 100). Each object should include at least one identity signal: email (or email_sha256), phone (or phone_sha256), full_name (or first_name+last_name), or address attributes (address_1, city, state, zip). All attributes are optional — include only what you have. Any extra attributes you include are echoed back unchanged.
object
Primary email address.
Phone number in any standard format.
Lowercase-hex SHA-256 hash of a normalized email address, for clients whose own systems never expose raw email addresses (e.g. data co-op / clean-room partners using the same hashing convention). The platform passes this through without re-hashing. Do not submit an already-hashed value in email — it would be hashed a second time and never match.
Lowercase-hex SHA-256 hash of a normalized phone number. Same pre-hashed semantics as email_sha256.
Optional convenience field. When provided (and first_name / last_name are absent), the engine parses this into first_name, middle_name, last_name, and name_suffix automatically. The parsed components are used for matching; the original full_name value is echoed back unchanged.
Generational suffix (e.g. JR, SR, III).
Additional raw email addresses beyond email, tried as extra match permutations.
Pre-hashed counterpart to emails.
Additional raw phone numbers beyond phone, tried as extra match permutations.
Pre-hashed counterpart to phones.
Additional addresses beyond address_1/city/state/zip, tried as extra match permutations.
object
Street address line 1.
Street address line 2 (apt, suite, etc.).
Two-letter US state code.
5- or 9-digit ZIP code.
Date of birth — any parseable date format (e.g. YYYY-MM-DD).
A previously-issued platform id (format CLIENTCODE_TIER_HASH, e.g. returned by a prior call to this endpoint or a matched-segment delivery). Resolved server-side before matching. An id that doesn’t resolve (foreign, expired, or a derived/unmatched-tier id) is dropped and the row matches on its other identity signals, if any.
Enrichment attribute names to append on match — every attribute must be a valid audience attribute (see GET /v1/catalog/fields). Mutually exclusive with template_id. If neither is provided, the Standard IAG attribute set (all attributes with product_usage containing audience) is used. Individual-level attributes (e.g. age, gender) come back null per row when that row’s match_level doesn’t qualify for individual-level data (see match_level below) — this is expected, not an error. Request only the attributes valid for the match_level(s) you accept if you want to avoid nulls.
Pre-built enrichment bundle ID. Only standard_iag is valid (see templates[] in GET /v1/catalog/fields). Mutually exclusive with field_list. If neither is provided, the Standard IAG attribute set is used.
Filter results to specific match levels. I = individual, H = household, D = digital (email/phone only match), S = spatial (nearby-address proximity match), A = address-level. Defaults to all 5 levels (['I', 'H', 'D', 'S', 'A']) if omitted. Restricting this also restricts which attributes come back populated — see field_list above.
Responses
Section titled “Responses”Matched records.
object
One output record per input record — matched or not. Matched rows carry a resolved iag_person_id, match_level/match_type/match_confidence, and (when requested) enrichment attributes. Unmatched rows carry match_level/match_type/match_confidence: null and a best-effort derived iag_person_id (see iag_person_id below) computed from the row’s own identity signals, or null if none qualified. Use match_count vs record_count to distinguish real matches from derived-only rows — only real matches are billed. Input attributes are echoed back unchanged; resolved enrichment attributes are added alongside them.
object
Correlates a matched output row back to its position in the submitted records array (1-indexed as a string when the input didn’t supply one).
Present when the request included email_sha256, echoed back unchanged.
Present when the request included phone_sha256, echoed back unchanged.
Present when the request included full_name; the original submitted value, echoed back unchanged. Null when the request did not include one.
Echoed back when present on input, or populated from full_name parsing when the request supplied full_name without first_name/last_name.
Generational suffix (e.g. JR, SR, III). Echoed back when present on input, or populated from full_name/last_name parsing.
Additional raw emails from the request, echoed back unchanged.
Additional pre-hashed emails from the request, echoed back unchanged.
Additional raw phones from the request, echoed back unchanged.
Additional pre-hashed phones from the request, echoed back unchanged.
Additional addresses from the request, echoed back unchanged.
object
Org-scoped, non-reversible identifier — never a raw internal id. Format: CLIENTCODE_TIER_HASH. TIER is 01 for a real graph match (see match_level/match_type/match_confidence) or 02–05 for a best-effort id deterministically derived from the row’s own identity signals when it did NOT match (name+address, email, name+phone, or name+zip, in that priority order). null when the row is unmatched and no identity signal qualified for derivation. A tier-01 id may be resubmitted as input (see iag_person_id on the request schema above) to re-resolve the same match; derived (tier 02–05) ids cannot be.
Granularity of the match. I = individual, H = household, A = address-level, S = spatial (nearby-address proximity match), D = digital (email/phone only match). Present only on matched records (null, not a derived value, on unmatched rows).
Matching strategy that produced the result (e.g. graph_name_email_match, vector_name_address_match, spatial_match). Present only on matched records.
Confidence score for the match (0–1). Present only on matched records.
Requested enrichment attributes keyed by column name (e.g. acs_housing_units, usda_median_hh_income_2023). Only present when field_list or template_id was provided and the record matched.
object
Total number of input records processed.
Number of records that resolved to a known identity.
Match_count / record_count.
Conservative platform estimate in USD for usage accepted for delivery (e.g. 0.30 means $0.30 estimated). This legacy-named field is not a local credit debit or finalized invoice amount; unmatched records emit no usage.
Unique identifier for this match run. Pass to GET /v1/match/runs/{runId} to retrieve full details or audit this call later. Requires ‘discovery’ scope to read.
Example
{ "records": [ { "match_level": "I" } ]}Invalid request — malformed body, missing required attribute, or failed validation. See error and message for details.
object
Stable machine-readable error code (e.g. INVALID_STATUS_TRANSITION, BILLING_INSUFFICIENT_BALANCE). Always present.
Human-readable explanation of the error.
Alternate machine-readable code — present on some endpoints as an alias for error for backward compatibility.
Opaque support/debug identifier when available.
Examples
{ "error": "Bad Request", "code": "MISSING_SEGMENTS", "message": "segment_ids is required for filter audiences."}Missing or invalid Bearer token. Obtain one via POST /v1/auth/token. When a token was supplied but rejected, code distinguishes TOKEN_EXPIRED (the token’s lifetime has passed — request a new one via POST /v1/auth/token and retry) from TOKEN_INVALID (malformed or revoked — re-authenticate).
object
Stable machine-readable error code (e.g. INVALID_STATUS_TRANSITION, BILLING_INSUFFICIENT_BALANCE). Always present.
Human-readable explanation of the error.
Alternate machine-readable code — present on some endpoints as an alias for error for backward compatibility.
Opaque support/debug identifier when available.
Examples
{ "error": "Unauthorized: Missing or invalid Authorization header"}{ "error": "Unauthorized", "code": "TOKEN_EXPIRED", "message": "Your session has expired. Please sign in again."}The request cannot proceed on billing grounds. BILLING_INSUFFICIENT_BALANCE applies only to prepay accounts and includes required, available, and shortfall in USD. BILLING_POSTPAY_CEILING_EXCEEDED applies to an account ceiling; BILLING_CONSUMER_POSTPAY_CEILING_EXCEEDED applies to an agency child’s routed ceiling. Both ceiling responses include projected accrued and configured ceiling in USD.
object
Stable machine-readable error code (e.g. INVALID_STATUS_TRANSITION, BILLING_INSUFFICIENT_BALANCE). Always present.
Human-readable explanation of the error.
Alternate machine-readable code — present on some endpoints as an alias for error for backward compatibility.
Opaque support/debug identifier when available.
Examples
{ "error": "Insufficient balance", "code": "BILLING_INSUFFICIENT_BALANCE", "message": "Insufficient effective balance", "required": 1, "available": 0.75, "shortfall": 0.25}{ "error": "Billing capacity unavailable", "code": "BILLING_POSTPAY_CEILING_EXCEEDED", "message": "Postpay ceiling would be exceeded", "accrued": 105, "ceiling": 100}Token is valid but lacks the required scope for this endpoint. Check the endpoint description for the required scope (discovery, purchase, or account).
object
Stable machine-readable error code (e.g. INVALID_STATUS_TRANSITION, BILLING_INSUFFICIENT_BALANCE). Always present.
Human-readable explanation of the error.
Alternate machine-readable code — present on some endpoints as an alias for error for backward compatibility.
Opaque support/debug identifier when available.
Examples
{ "error": "SCOPE_REQUIRED", "message": "This endpoint requires the purchase scope."}BILLING_NOT_READY — the billing account/route isn’t active. IDEMPOTENCY_KEY_CONFLICT — the Idempotency-Key header was already used with a different request body. IDEMPOTENCY_REQUEST_IN_PROGRESS — another request with this key is in flight; retry after the seconds in Retry-After.
object
Example
{ "code": "BILLING_NOT_READY"}A required billing provider integration is temporarily unavailable.
object
Stable machine-readable error code (e.g. INVALID_STATUS_TRANSITION, BILLING_INSUFFICIENT_BALANCE). Always present.
Human-readable explanation of the error.
Alternate machine-readable code — present on some endpoints as an alias for error for backward compatibility.
Opaque support/debug identifier when available.
Examplegenerated
{ "error": "example", "message": "example", "code": "example", "request_id": "example"}