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 — theX-Rate-Limit-Retry-After-Secondsheader 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— a200doesn’t guarantee data was found;isRetryabledecides 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 traffic | Response 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.
Python#
Needs pip install requests and AGGK_API_KEY set in your environment:
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 retryingJavaScript#
Node.js 18 or newer (built-in fetch) — save as client.mjs and run node client.mjs:
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
}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.