Calling the API from Code

The Quickstart made one call. This is the shape that survives production. A small helper that reads the key from the environment, honors rate-limit headers, retries what is retryable, and branches on isSuccess. Both examples call the free test environment; switch /test/ to /live/ when you go to production.

What the helper must do#

  • Read the key from an environment variable — never hardcode it in source files. See API Keys.
  • Set a generous client timeout — 60 seconds for synchronous enrichment. See Timeouts below.
  • On 429, wait and retry — the X-Rate-Limit-Retry-After-Seconds header says exactly how long. See Rate Limit Headers.
  • On 5xx, retry with backoff — a few attempts with growing delays, then give up and report.
  • Branch on isSuccess — a 200 doesn’t guarantee data was found; isRetryable decides whether the row goes back in the queue. See Handle Failed Enrichments.

Timeouts#

Most synchronous enrichments answer in well under a second; a few take tens of seconds. A person already on file comes straight back. One we have never seen, or whose data is stale, is refreshed from our sources while you wait — that is the slow tail.

POST /person/enrich, live trafficResponse time
Median~0.2 s
95th percentile~2 s
99th percentile~5 s
Slowest observed~26 s

Set the client timeout to 60 seconds. That clears every request we have observed with room to spare; a 5- or 10-second timeout, common as an HTTP-client default, abandons requests that were about to succeed. Our gateway closes any request still open after 180 seconds with a 504 that has no JSON body, so don’t parse a 504.

Treat a timeout like a 5xx: back off and retry. The enrichment keeps running on our side after your client gives up, so the retry is usually answered from the refreshed profile.

Warning: A request you abandon can still complete — and be charged — on our side. Retry timeouts a bounded number of times, not in a tight loop. If you are enriching more than a handful of people, use bulk enrichment instead: it has no client timeout to tune and bills item by item. See Enrich a CRM List.

Python#

Needs pip install requests and AGGK_API_KEY set in your environment:

Python
import os
import time

import requests

API_BASE = "https://api.aggknowledgeai.com/v2/test"
API_KEY = os.environ["AGGK_API_KEY"]

def call_api(path, body, max_attempts=4):
    for attempt in range(1, max_attempts + 1):
        try:
            response = requests.post(
                API_BASE + path,
                headers={"x-api-key": API_KEY},
                json=body,
                timeout=60,
            )
        except (requests.Timeout, requests.ConnectionError):
            if attempt < max_attempts:
                time.sleep(2 ** attempt)
                continue
            raise
        if response.status_code == 429:
            wait = response.headers.get("X-Rate-Limit-Retry-After-Seconds", "1")
            time.sleep(int(wait))
            continue
        if response.status_code >= 500 and attempt < max_attempts:
            time.sleep(2 ** attempt)
            continue
        response.raise_for_status()
        return response.json()
    raise RuntimeError(f"gave up after {max_attempts} attempts")

result = call_api("/person/enrich", {
    "professionalSocialMediaUrl": "https://linkedin.com/in/danielentrup/",
})
if result["isSuccess"]:
    print(result["data"]["firstName"], result["data"]["lastName"])
elif result["isRetryable"]:
    ...  # transient - queue for a later retry
else:
    ...  # bad input - fix the identifier rather than retrying

JavaScript#

Node.js 18 or newer (built-in fetch) — save as client.mjs and run node client.mjs:

JavaScript
const API_BASE = "https://api.aggknowledgeai.com/v2/test";
const API_KEY = process.env.AGGK_API_KEY;

const sleep = (seconds) => new Promise((r) => setTimeout(r, seconds * 1000));

async function callApi(path, body, maxAttempts = 4) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      // The timeout covers reading the body too, so the whole attempt sits in the try.
      const response = await fetch(`${API_BASE}${path}`, {
        method: "POST",
        headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
        body: JSON.stringify(body),
        signal: AbortSignal.timeout(60_000),
      });
      if (response.status === 429) {
        const wait = response.headers.get("X-Rate-Limit-Retry-After-Seconds");
        await sleep(Number(wait ?? 1));
        continue;
      }
      if (response.status >= 500 && attempt < maxAttempts) {
        await sleep(2 ** attempt);
        continue;
      }
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${await response.text()}`);
      }
      return await response.json();
    } catch (err) {
      const timedOut = err.name === "TimeoutError" || err.name === "AbortError";
      if (timedOut && attempt < maxAttempts) {
        await sleep(2 ** attempt);
        continue;
      }
      throw err;
    }
  }
  throw new Error(`gave up after ${maxAttempts} attempts`);
}

const result = await callApi("/person/enrich", {
  professionalSocialMediaUrl: "https://linkedin.com/in/danielentrup/",
});
if (result.isSuccess) {
  console.log(result.data.firstName, result.data.lastName);
} else if (result.isRetryable) {
  // transient - queue for a later retry
} else {
  // bad input - fix the identifier rather than retrying
}
Warning: In JavaScript, personId and company id values are 64-bit integers that JSON.parse silently rounds above Number.MAX_SAFE_INTEGER. Before you persist IDs, read the precision warning in Person Identifiers.