CoverClicks

Documentation

Buyer API reference

Upload the people on your list who have gone quiet. Each morning we check them against job-search activity across the network and deliver the ones who are actively looking, as a file, a webhook, or on demand through the lookup API. You pay only for delivered people: the first 500 are free, then $0.15 each. Accounts are self-serve at portal.coverclicks.com/buyer-apply.

How people are identified

Every API takes and returns the SHA-256 of the email address, trimmed and lowercased, as 64 lowercase hex characters. Apply no other transformation: no Gmail dot-stripping, no plus-address removal, no Unicode normalization.

hashed_email = sha256_hex(email.strip().lower().encode("utf-8"))

# "  Jane.Doe@Example.com " -> "jane.doe@example.com" -> 2e6d7c1f...

You may upload raw addresses instead (header email); we hash them on arrival and the raw addresses are never kept. We never return a raw email address, a name, a date of activity, a hit count, or the name of a site.

Your own record id. Add an optional second column, external_id, holding the id of the record in your own system (up to 128 characters). Every match we deliver, in the daily file, the webhook and the connectors, carries it back, so you can update the right record without keeping a hash lookup on your side.

List upload

Upload through the dashboard or by API. The body is a CSV with a header row of hashed_email or email, an optional external_id column, and one row per person. Each upload replaces your current list; people removed from the list stop being matched the next morning.

hashed_email,external_id
5d41402a...0a1b,cand_88213
7f3a9c0e...41de,cand_88290
curl -X POST https://portal.coverclicks.com/api/buyer/v1/dormant/upload \
  -H "Authorization: Bearer ccb_..." \
  -H "Content-Type: text/csv" \
  --data-binary @dormant.csv
  • Key: issued on the dashboard API key tab (shown once).
  • Limits: 20 uploads per hour, bodies up to 800 MB.
  • Answers: 200 with the stored row count; 401 bad key; 413 too large; 429 over the hourly limit.

Daily match file

Every morning a CSV appears on your dashboard holding only the people from your list who were active in the last 30 days. People who are not active are never delivered and never charged. A person is delivered again only when they show new activity, and no more often than the interval you set (7 to 90 days, default 30). A daily cap in dollars or matches is optional.

match_status,hashed_email,matched_at_utc,job_search_recency_days,job_search_intensity,job_search_duration_days,cross_site_activity_count,dominant_occupation_cluster,other_occupation_clusters,external_id
hit,5d41402a...0a1b,2026-10-20T10:58:41Z,2,high,14,3,Healthcare,Office & Administrative,cand_88213

The last column, external_id, is your own record id from the upload, or empty if you did not send one.

Files whose name ends in -api hold matches that were delivered in real time rather than in the morning run. The six signal columns are described under Signal fields.

Real-time webhook

Instead of waiting for the morning file, we can POST each match to an HTTPS address you host the moment we find it. Enter the address on the Reactivation signals tab; we switch it on, usually within one business day, and show your signing secret on the API key tab. Same price and same settings as file delivery.

POST https://example.com/coverclicks-matches
Content-Type: application/json
X-CoverClicks-Event: buyer.match_signal
X-CoverClicks-Source: buyer_list
X-CoverClicks-Signature: sha256=<hex HMAC-SHA256 of the raw body, keyed with your signing secret>

{
  "event_id": "f0c9...",
  "source": "buyer_list",
  "buyer_id": "f6c8c1f0-...",
  "file_date": "2026-10-20",
  "hashed_email": "5d41402a...0a1b",
  "external_id": "cand_88213",
  "matched_at": "2026-10-20T10:58:41Z",
  "match_status": "hit",
  "job_search_recency_days": 2,
  "job_search_intensity": "high",
  "job_search_duration_days": 14,
  "cross_site_activity_count": 3,
  "dominant_occupation_cluster": "Healthcare",
  "other_occupation_clusters": "Office & Administrative"
}
  • One request per matched person. Answer with any 2xx status within 10 seconds.
  • Verify the signature server-side: compute HMAC-SHA256 over the raw request body with your secret and compare to the hex after sha256=.
  • On a non-2xx answer or a timeout we stop and resume from that person on the next run, so nothing is skipped. event_id is stable, so a repeat delivery can be ignored.
  • Rotate the secret by asking us to clear and re-set the address; the old value stays valid until then.
Zapier, Make and n8n can receive this webhook directly in your own account, with nothing needed from us. See Integrations.

Profile lookup API

Ask, for any hashed email, whether the network has seen that person in the last 90 days, which occupations and employers they are interested in, and their in-market signals. On for every buyer account; the same key as the upload API.

curl https://portal.coverclicks.com/api/buyer/v1/profile/lookup \
  -H "Authorization: Bearer ccb_..." \
  -H "Content-Type: application/json" \
  -d '{"hashed_email": "5d41402abc4b2a76b9719d911017c592a3b7e1f0c9d8e7f6a5b4c3d2e1f00a1b"}'

Send {"hashed_emails": ["...", "..."]} for up to 100 people per request. A single lookup also works as a GET with ?hashed_email=....

{
  "results": [
    {
      "hashed_email": "5d41402a...0a1b",
      "found": true,
      "status": "match",
      "active_last_30_days": true,
      "job_search_recency_days": 3,
      "job_search_intensity": "high",
      "job_search_duration_days": 12,
      "cross_site_activity_count": 2,
      "dominant_occupation_cluster": "Healthcare",
      "other_occupation_clusters": "Office & Administrative",
      "occupations": [
        { "title": "Registered Nurse", "soc": "29-1141" },
        { "title": "Licensed Practical Nurse", "soc": "29-2061" }
      ],
      "employers": [
        { "name": "HCA Healthcare" }
      ]
    }
  ],
  "allowance_remaining": 9959
}
  • Match = anyone the network has seen in the last 90 days. The daily file only carries people active in the last 30; use active_last_30_days to tell them apart.
  • Up to three occupations and three employers, strongest first. soc is the US Standard Occupational Classification code when known.
  • Signal fields are null when we hold interest data but no activity record. A person with signals but no interest data is still a match with empty lists.
  • Each match uses 1 of your matches, from the same free 500 and prepaid credits as reactivation signals. A lookup that finds nothing is free. When matches are used up the answer is status: "out_of_credits", found: false, and nothing is charged. allowance_remaining is null on unlimited accounts.
  • Results come back in the order asked, one per distinct hash. Data is refreshed once a day around 11:00 UTC.

Signal fields

The same six fields appear in the daily file, the webhook and the lookup API. The daily file and the webhook also carry external_id, your own record id, when you supplied one.

job_search_recency_days
Days since the person's last job-search activity. 7 or less is hot.
job_search_intensity
low, medium or high, from the number of active days in the last 30.
job_search_duration_days
How long the current search has been going.
cross_site_activity_count
How many sites the person is active on. The sites are never named.
dominant_occupation_cluster
The main job area they are looking in, when known (for example Healthcare).
other_occupation_clusters
Any other job areas they are also looking in, separated by semicolons. Blank when none.

Limits and errors

  • Lookup: 3,000 requests per minute per account, each with up to 100 hashes. Beyond that, 429 with resetSeconds.
  • Upload: 20 per hour, 800 MB per body.
  • 400 a value is not 64 hex characters, no hash was sent, or more than 100 were sent.
  • 401 missing or wrong key. 403 the feature is switched off for the account.

Questions: support@coverclicks.com.