Datamagnet
Real-time B2B people and company data API

- Fields per profile
- 75+
- Typical response
- Sub-200 ms
- Documented endpoints
- 22
- MCP tools
- 17
- Signal types
- 7
- Developers
- 5,000+
Datamagnet is a REST API that returns structured JSON for a public professional profile, company page, post or job posting at the moment you ask for it, instead of serving a copy from a database that was accurate last quarter. It also offers ICP search over a stored profile warehouse, and Signals that watch people and topics and push alerts to webhooks and email. Teams use it through REST, an MCP server for AI agents, and HubSpot and Zoho extensions.
The problem
RevOps, sales, recruiting and market-intelligence teams need to know what a person or company looks like right now: current title, headcount, recent posts, funding. Static B2B databases go stale within months, and building live collection in-house means solving parsing, response normalisation, caching, rate limiting, per-request billing and reliability all at once. Customers also need the same response shape on every call so their pipelines never break on a missing key.
How it is built
Edge and routing. A Cloudflare Worker fronts the API domain and splits traffic between two cloud backends (AWS App Runner and Google Cloud Run) with connection-level failover between them. It only retries failures that happen before the origin saw the request: credits are deducted before a response is written, so a timed-out request may already have been processed and retrying it would charge the customer twice. Every response carries a header naming the backend that served it, so incidents can be attributed.
API layer. The core is a Flask application behind gunicorn. Every data route passes through one decorator chain: authentication, rate limiting, credit resolution and deduction, then request logging and endpoint analytics. Responses are normalised to a stable shape (every documented key is always present, with null, an empty string or an empty list when a value is unknown). Callers choose a cache mode per request (serve if present, serve only if recent, or always fetch live). Accounts, API keys and request logs live in MongoDB; Redis provides the response cache and a write queue, wrapped in a circuit breaker so a Redis outage degrades to live fetches rather than errors.
Data warehouse. Profiles the API fetches are written asynchronously through a Redis queue into a PostgreSQL warehouse run by a separate FastAPI service, with batched upserts, de-duplication and a dead-letter queue. The warehouse powers the people and company database-search endpoints and the ICP filter suggestions, using derived filter columns, a materialised search index and PgBouncer in front of Postgres. An hourly aggregation job rolls raw API logs into hourly and daily analytics, and a scheduled Cloud Run job prunes the raw logs once they are folded in.
Surfaces. A Next.js customer app (API keys, request logs, billing, Signals management) authenticates with AWS Cognito; a separate Next.js admin console covers users, credit configuration, endpoint health, rate limits and provider metrics. Public docs are Mintlify with an OpenAPI spec and an interactive playground. The MCP server exposes the documented endpoints as 17 agent tools and supports both bearer-key passthrough and OAuth 2.1 with PKCE, with the customer's API key never leaving the server. Lifecycle email runs as its own always-on process so an email-provider hang can never block a payment webhook or a customer request.
What it taught me
- Never retry a request that may already have been charged: the edge router retries only connection-level failures and reports its own timeouts as such, because credits are deducted before the response is written.
- A fixed response shape, with every key present and null where unknown, removed a whole class of customer parsing bugs; shipping it meant a documented breaking change rather than another round of patches.
- Keep slow or bursty work off the request path: warehouse ingestion and lifecycle email run as separate processes behind a queue, so a slow Postgres write or an email-provider hang never blocks a customer call.
Architecture
Clients (REST callers, the MCP server, CRM extensions and the web app) reach a Cloudflare Worker that routes each request to one of two cloud backends running the Flask API and fails over on connection errors. The API authenticates the key and deducts credits against MongoDB, checks Redis for a cached response, and otherwise fetches live from upstream data providers. Fetched profiles are queued in Redis and written by a worker into the PostgreSQL warehouse, which also serves database search and ICP filters. Signal requests are proxied to the separate Signals engine, and scheduled jobs roll request logs into analytics.
Layer 1
ClientsClient
REST, MCP, CRM apps, web app
→ Cloudflare Worker (HTTPS)
Layer 2
Cloudflare WorkerEdge
Weighted routing and failover
→ Flask API (Routes, fails over)
Layer 3
Flask APIService
Auth, credits, rate limits, normalisation
→ MongoDB (Auth, credits, logs) → Redis (Cache, enqueue) → Upstream data providers (Live fetch) → Profile warehouse (Search queries) → Signals engine (Proxies /signal)
Layer 4
MongoDBStore
Accounts, keys, request logs
→ Analytics jobs (Rollup, prune)
RedisStore
Response cache, write queue
→ Profile warehouse (Batched writes)
Upstream data providersExternal
Live profile and post fetch
Signals engineWorker
Monitors, alerts, leads
Layer 5
Analytics jobsWorker
Hourly rollups, log retention
Profile warehouseStore
FastAPI on PostgreSQL, ICP search
Stack
Backend
- Python
- Flask
- gunicorn
- FastAPI
- SQLAlchemy
- Pydantic
- OAuth 2.1 + PKCE
Data
- PostgreSQL
- PgBouncer
- MongoDB
- Redis
Infrastructure
- Cloudflare Workers
- AWS App Runner
- Google Cloud Run
- Cloud Run Jobs
- AWS Cognito
- AWS SES
- Docker
- Coolify
- Vercel
- GitHub Actions
- Sentry
- PostHog
Frontend
- Next.js
- React
- Tailwind CSS
- Radix UI
- Mintlify
- Sanity
AI
- OpenAI API
- Model Context Protocol