Developer API

Match people, normalize addresses, and enrich records.

Use Linksync to compare person records with Splink, parse messy US addresses, match to OpenStreetMap features, and return locality-aware place details.

Quick start

curl -X POST https://your-domain.example/api/normalize \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"address":"47 Glen Avenue, Newton, MA 02459"}'

The public demo uses /api/normalize/demo. Production API requests should use a bearer token from /oauth/token with client credentials.

Overview

1

Match people

Compare CRM records, imports, or caller-supplied candidate blocks using Splink.

2

Parse

Convert free-text or structured inputs into consistent address components.

3

Match

Optionally resolve addresses to OSM features with coordinates and IDs.

4

Enrich

Return main city, locality, state, and administrative area details where available.

POST /oauth/token

Authentication

Request an OAuth-style bearer token, then send it as Authorization: Bearer <access_token> on API calls. Legacy ?key=... access still works for now but bearer auth is preferred.

Client credentials grant

grant_type=client_credentials&client_id=YOUR_API_KEY&client_secret=YOUR_OAUTH_CLIENT_SECRET

Response

{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600
}
POST GET /api/normalize

Normalize a free-text address

Send a single address string. Linksync parses it into address components. Add match=true to also attempt an OSM building or place match.

address
Required. Full address string for POST body or GET query string.
match
Optional query parameter. Boolean, defaults to false.
locality_output_mode
Optional request field. One of main_city, replace_city, or separate_field.

POST request

{
  "address": "47 Glen Avenue, Newton, MA 02459",
  "locality_output_mode": "separate_field"
}

Example response

{
  "street": "Glen Avenue",
  "housenumber": "47",
  "postcode": "02459",
  "city": "Newton",
  "locality": "Newton Centre",
  "admin_area": "Middlesex County",
  "admin_area_type": "county",
  "state": "MA",
  "country_code": "US",
  "lat": 42.298,
  "lon": -71.203
}
POST GET /api/normalize/structured

Normalize a structured address

Use this endpoint when your source system already separates street, city, state, and postcode fields.

housenumber
Required with street. Street number, including unit suffix if present.
street
Required with housenumber. Street name.
city/state/postcode
At least one of these should be supplied. Postcode lookup can fill missing city/state details.
countrycode
Optional. Defaults to the configured country, currently US.

POST request

{
  "housenumber": "47",
  "street": "Glen Avenue",
  "city": "Newton",
  "county": "Middlesex",
  "state": "MA",
  "postcode": "02459",
  "countrycode": "US"
}
POST /api/splink/match /api/splink/match/records

Person matching

Person matching requires Match People to be enabled on your account. Use bearer auth from /oauth/token.

Match an uploaded person file

After uploading and processing a person-matching CSV in the UI or upload API, call Splink match with the upload id. Linksync automatically uses your primary person parquet/model.

{
  "upload_id": 456,
  "matching_scheme": "person_balanced_v1",
  "use_trained_model": true
}

Match direct JSON records

Use this endpoint when you want to send people directly instead of uploading a CSV. Linksync builds temporary Splink input parquet and returns an upload_id that can be used with progress and download endpoints.

{
  "blocking_mode": "splink",
  "matching_scheme": "person_default_v1",
  "use_trained_model": true,
  "parse_address": true,
  "match_address": true,
  "records": [
    {
      "row_id": "import-55",
      "full_name": "Simon French",
      "email": "simon@example.com",
      "address": "47 Glen Avenue, Newton, MA 02459"
    }
  ]
}
matching_scheme
Optional. One of person_default_v1, person_conservative_v1, person_balanced_v1, person_import_v1, household_v1, or organization_v1.
use_trained_model
Optional, defaults to true. Set to false to ignore the stored trained model and use the selected scheme settings.
blocking_mode
Optional for direct records. splink uses Linksync/Splink blocking. crm uses caller-supplied block ids.
parse_address
Optional. Parse single-line addresses with libpostal before creating Splink input.
match_address
Optional. Match parsed or structured addresses to Photon/OSM and use verified OSM-derived address fields.

Accepted person and address fields

Records may include full_name or first_name plus last_name, and optional fields such as middle_name, dob, gender, email, phone, organization_name, and person_id.

Address input may be a single string in address, address_line, or full_address; an address object; or top-level components such as street, housenumber, city, state, and postcode. Request-level parse_address and match_address can also be overridden per record.

POST /api/splink/match/records

CRM-supplied blocking

When your CRM has already selected candidate blocks, send blocking_mode: "crm". Linksync only compares records where primary_records[].crm_block_id equals records[].crm_block_id.

{
  "blocking_mode": "crm",
  "matching_scheme": "person_default_v1",
  "use_trained_model": true,
  "parse_address": true,
  "match_address": true,
  "primary_records": [
    {
      "row_id": "crm-1001",
      "crm_block_id": "block-a",
      "full_name": "Simon French",
      "address_line": "47 Glen Avenue, Newton, MA 02459"
    }
  ],
  "records": [
    {
      "row_id": "import-55",
      "crm_block_id": "block-a",
      "first_name": "Simon",
      "last_name": "French",
      "address": {
        "street": "Glen Avenue",
        "housenumber": "47",
        "postcode": "02459"
      }
    }
  ]
}
CRM blocking requires both primary_records and records. Direct JSON matching is intended for small/interactive jobs; use the CSV upload workflow for larger files.
POST /api/uploads/{id}/remove-pii

Remove PII but keep training analysis

Use this endpoint when a user wants uploaded person/address data removed while keeping the Splink trained model summary and training analysis charts.

Linksync deletes source files, result files, Splink input CSV/parquet files, and Splink match outputs. It keeps the trained model JSON and training chart HTML files, so training analysis remains available.

After PII is removed, stored-upload matching against that primary file cannot run because the primary parquet has been deleted. Use direct/API records or re-process source data when matching needs the primary records again.

Locality output modes

Locality output lets clients choose whether ZIP-level neighborhoods and villages should appear as the returned city or as separate fields.

ModeBehavior
main_cityReturn the canonical main city only.
replace_cityReplace city with a nearby locality when Linksync can do so safely.
separate_fieldKeep city as the main city and add locality, admin_area, and admin_area_type when available.
Locality output is distance guarded. Linksync will not return a locality candidate that is implausibly far from the matched address coordinates. For a non-technical explanation, see How locality matching works.

Errors and geographic limits

  • 400: missing or invalid request input.
  • 401: missing, expired, or invalid bearer token.
  • 500: unexpected server error, returned as {"error":"message"}.

Results are filtered to the configured country, currently US. Some deployments may also be restricted to a test state such as Massachusetts.