Skip to content

maniculehq/api-compat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

api-compat

Drop-in compatibility proxies for enrichment APIs. Migrate without rewriting your integration.

V1 ships one route: People Data Labs → Nyne.

If you're already on PDL, you change one base URL (and add one header) and your existing code routes through Nyne instead. The request body stays the same. The response shape stays the same. Your parsing code, your downstream pipelines, your tests — all unchanged.

Built and maintained by Manicule.


Quick start

# Before — your existing PDL code:
curl -X POST https://api.peopledatalabs.com/v5/person/enrich \
  -H "X-Api-Key: $PDL_KEY" \
  -d '{"email": "person@example.com"}'

# After — same code, different URL, swap creds:
curl -X POST https://compat.manicule.dev/pdl/v5/person/enrich \
  -H "X-Api-Key: $NYNE_KEY" \
  -H "X-Api-Secret: $NYNE_SECRET" \
  -d '{"email": "person@example.com"}'

You get back PDL-shaped JSON:

{
  "status": 200,
  "likelihood": 10,
  "data": {
    "full_name": "Jane Doe",
    "first_name": "Jane",
    "last_name": "Doe",
    "emails": [{ "address": "jane@…", "type": "personal", ... }],
    "phone_numbers": ["+1…"],
    "job_title": "Engineer",
    "job_company_name": "ACME",
    "linkedin_url": "https://linkedin.com/in/janedoe",
    "experience": [ ],
    "education": [ ],
    "location_name": "San Francisco, CA"
  }
}

The PDL Python SDK (peopledatalabs) parses this directly.


What the proxy does

PDL Nyne
Auth one header (X-Api-Key) two headers (X-API-Key + X-API-Secret)
Mode synchronous synchronous (default)
Response wrapper {status, likelihood, data} {success, data: {result}}
Naming snake_case camelCase
Emails array of {address, type, ...} array of strings (altemails)
Phones phone_numbers[] + phones[] fullphone[].fullphone
Work history experience[] (nested company + title) organizations[] (flat)
Education education[] (nested school) schools_info[] (flat)
Location 10+ flat location_* fields one free-form string
Social flat linkedin_url, twitter_url, etc. social_profiles.{platform}.url

The full mapping spec lives at mappings/pdl_v5_person_enrich.yaml.


Field-level honesty

Some PDL fields have no equivalent in Nyne's response. The proxy returns them as null rather than omitting them, so existing PDL parsing code doesn't break with KeyError.

Fields that come through (Nyne returns them):

  • full_name, first_name, last_name, headline, sex
  • All social profile URLs + usernames (LinkedIn, Twitter, GitHub, Facebook)
  • linkedin_connections
  • personal_emails, recommended_personal_email, emails[]
  • mobile_phone, phone_numbers[], phones[]
  • job_title, job_company_name, job_start_date, job_summary (derived from current org)
  • experience[], job_history[], education[]
  • location_name, location_locality, location_region, location_country (parsed from the free-form Nyne string — best-effort)

Fields that come back null because Nyne doesn't expose them:

  • birth_date, birth_year, middle_name, middle_initial
  • work_email (Nyne doesn't tag email types)
  • industry, inferred_salary, inferred_years_experience
  • All job_company_* enrichment fields (size, founded, industry, location, revenue, employee count, …)
  • location_metro, location_continent, location_street_address, location_postal_code, location_geo
  • interests[], skills[], certifications[], languages[]
  • possible_emails, possible_phones, possible_profiles, possible_street_addresses
  • num_sources, num_records, first_seen, dataset_version

If your code depends on any of those, this proxy isn't a drop-in for your use case. The mapping file lists everything; check it before migrating.


Run locally

git clone https://github.com/maniculehq/api-compat
cd api-compat
python3.12 -m venv .venv && source .venv/bin/activate
pip install fastapi "uvicorn[standard]" httpx pyyaml
uvicorn proxy.main:app --reload

Test against your Nyne credentials:

curl -X POST http://localhost:8000/pdl/v5/person/enrich \
  -H "X-Api-Key: $NYNE_KEY" \
  -H "X-Api-Secret: $NYNE_SECRET" \
  -d '{"email": "you@yourdomain.com"}'

Run the tests

pip install pytest pytest-asyncio respx
pytest -v

31 tests cover the request transform, response transform, FastAPI endpoint, and error handling.


Deploy

The repo ships with a Dockerfile and fly.toml:

fly launch --no-deploy   # creates the app, skip if it already exists
fly deploy

Or any container host — Cloud Run, Render, Railway, Heroku — works fine. The image is ~120MB and the service uses ~50MB resident RAM idle.


Limitations / roadmap

V1 covers /v5/person/enrich only. PDL has more endpoints:

  • /v5/person/search — Elasticsearch / SQL queries. Would need PDL query translation to Nyne's filter format. Not on the V1 roadmap.
  • /v5/person/identify — multi-match. Possible V2.
  • /v5/company/enrich — straightforward to add, blocked on the same field-mapping work. Open an issue if you need it.
  • Bulk endpoints — not planned. Loop in client code.

This isn't a complete PDL feature parity. It's a migration tool: get your enrichment pipeline pointed at Nyne with the smallest possible code change, then evolve toward Nyne's native API on your own schedule.


Why this exists

Manicule builds docs and developer marketing for AI infrastructure companies. Migration friction kills good products. When Nyne pitched themselves as a more accurate, cheaper PDL alternative, the natural question from every prospective customer was "how much engineering work to switch?" This proxy is the answer: about 60 seconds.

If you're a vendor building an API in a competitive category and want a drop-in compatibility layer that makes "we replaced their incumbent" the literal one-line change — we do this.


License

MIT

About

Drop-in API compatibility proxies for data enrichment vendors. V1: People Data Labs → Nyne.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors