Developer Docs

API & Webhook Documentation

Programmatic access to Kuration's data enrichment and list-building platform. Submit data, trigger enrichments, and receive results in real time.

Overview

Kuration provides two integration methods for programmatic access to our data enrichment and list-building platform:

Project Workflow API

Submit company data, trigger enrichment tools, and retrieve results via REST endpoints.

Webhooks

Receive real-time notifications when enrichment tasks complete — no polling required.

Base URL

https://api.kurationai.com/api/enterprise

Authentication

All API requests require your API key in the request header:

kur-api-key: YOUR_API_KEY

Contact us to receive your API key. API access is available on the Enterprise plan ($1,000/month).

Project Workflow API

The workflow follows three steps: submit company data, receive a row ID, then fetch enriched results.

1

Submit Company Data

Send a POST request with company information to a project

2

Receive Row ID

The API returns a row_id to track your submission

3

Fetch Results

Use project_id and row_id to retrieve the enriched data

GET/projects

List All Projects

Retrieve all projects accessible to your account.

Request

python
import requests

url = "https://api.kurationai.com/api/enterprise/projects"

headers = {
    "accept": "application/json",
    "kur-api-key": "YOUR_API_KEY"
}

response = requests.get(url, headers=headers)
print(response.json())

Response

Response
[
  {
    "id": "98e79cf8-87c9-49b0-9899-58edb6f3c98b",
    "name": "Tech Companies Q4",
    "creator_id": "user_abc123",
    "company_count": 150,
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-01-20T14:45:00Z"
  }
]
GET/projects/{id}

Get Project Details

Retrieve columns schema and sample data for a specific project.

Request

python
import requests

project_id = "YOUR_PROJECT_ID"
url = f"https://api.kurationai.com/api/enterprise/projects/{project_id}"

headers = {
    "accept": "application/json",
    "kur-api-key": "YOUR_API_KEY"
}

response = requests.get(url, headers=headers)
print(response.json())

Response

Response
{
  "columns": [
    { "col_id": "0674c9a3-...", "name": "company_name", "required": true },
    { "col_id": "4905e83c-...", "name": "website", "required": true },
    { "col_id": "466527f1-...", "name": "industry", "required": false }
  ],
  "first_company_data": {
    "company_name": "Acme Corporation",
    "website": "https://acme.com",
    "industry": "Technology"
  }
}
POST/projects/{id}/rows

Save Company Data

Submit company information to a project for enrichment.

Request

python
import requests

project_id = "YOUR_PROJECT_ID"
url = f"https://api.kurationai.com/api/enterprise/projects/{project_id}/rows"

headers = {
    "accept": "application/json",
    "Content-Type": "application/json",
    "kur-api-key": "YOUR_API_KEY"
}

data = {
    "company": {
        "company_name": "Acme Corporation",
        "website": "https://acme.com"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.json())

Response

Response
{
  "row_id": "Jxl8KwcI6bAHH8wdQRvs",
  "message": "Success",
  "error_detail": null
}
GET/projects/{id}/rows

Get All Rows

Retrieve all rows in a project with pagination. Use page and page_size query parameters to control results.

Request

python
import requests
import json

project_id = "YOUR_PROJECT_ID"
url = f"https://api.kurationai.com/api/enterprise/projects/{project_id}/rows"

headers = {
    "accept": "application/json",
    "kur-api-key": "YOUR_API_KEY"
}

params = {
    "page": 1,
    "page_size": 50
}

response = requests.get(url, headers=headers, params=params)
print(json.dumps(response.json(), indent=2))

Response

Response
{
  "rows": [
    {
      "id": "Jxl8KwcI6bAHH8wdQRvs",
      "company": {
        "company_name": { "value": "Acme Corporation", "status": "default" },
        "website": { "value": "https://acme.com", "status": "default" }
      }
    }
  ],
  "page": 1,
  "page_size": 50,
  "total": 150
}

Use pagination to efficiently retrieve large datasets. The default page_size is 50. Maximum page_size is 200.

GET/projects/{id}/rows/{row_id}

Get Row Results

Retrieve enriched company data after processing completes.

Request

python
import requests

project_id = "YOUR_PROJECT_ID"
row_id = "YOUR_ROW_ID"
url = f"https://api.kurationai.com/api/enterprise/projects/{project_id}/rows/{row_id}"

headers = {
    "accept": "application/json",
    "kur-api-key": "YOUR_API_KEY"
}

response = requests.get(url, headers=headers)
print(response.json())

Response

Response
{
  "id": "4d9ace8e-bdcf-401f-93db-a4b73d12cf13",
  "project_id": "98e79cf8-87c9-49b0-...",
  "company": {
    "company_name": {
      "name": "company_name",
      "value": "Acme Corporation",
      "status": "default",
      "is_loading": false
    },
    "website": {
      "name": "website",
      "value": "https://acme.com",
      "status": "default",
      "is_loading": false
    }
  }
}

When is_loading is true, the enrichment tool is still processing. Poll again after a short delay, or use webhooks for real-time notifications.

Webhooks

Webhooks notify your server in real-time when an enrichment tool completes processing. This eliminates the need to poll the API for results.

Payload Structure

JSON payload sent via POST to your webhook URL when a tool cell completes.

Headers

Content-Type: application/json
X-Kuration-Signature: <HMAC-SHA256 signature>

Example Payload

Response
{
  "event": "tool_output_ready",
  "project_id": "98e79cf8-87c9-49b0-9899-58edb6f312345",
  "row_id": "Jxl8KwcI6bAHH8wdQ123",
  "col_id": "466527f1-ef79-4cd6-bf03-c878681d1234",
  "value": "Technology",
  "status": "success",
  "timestamp": "2024-01-20T14:45:00.000Z"
}

Field Descriptions

FieldTypeDescription
eventstringEvent type (always "tool_output_ready")
project_idstringUUID of the project
row_idstringID of the row that was processed
col_idstringUUID of the tool column
valueanyThe result value from the tool
statusstring"success" or "error"
timestampstringISO 8601 timestamp

Webhook Handler Example

Complete Flask server to receive and verify Kuration webhooks.

python
from flask import Flask, request, jsonify
import hmac, hashlib

app = Flask(__name__)
WEBHOOK_SECRET = "YOUR_WEBHOOK_SECRET"

@app.route("/webhook", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-Kuration-Signature")
    if not signature:
        return jsonify({"error": "Missing signature"}), 401

    payload = request.get_data()
    expected = hmac.new(
        WEBHOOK_SECRET.encode("utf-8"),
        payload,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        return jsonify({"error": "Invalid signature"}), 401

    data = request.json
    # Process: data["event"], data["row_id"], data["value"], etc.
    return jsonify({"success": True}), 200

if __name__ == "__main__":
    app.run(port=5000)

Signature Verification

Verify webhook authenticity using HMAC-SHA256.

python
import hmac, hashlib

def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Security Best Practices

Always verify the HMAC signature before processing webhook payloads

Use constant-time comparison (hmac.compare_digest) to prevent timing attacks

Store your API key and webhook secret in environment variables — never hardcode them

Respond to webhooks within 5 seconds to avoid timeouts

Use HTTPS for your webhook endpoint

Need Help?

For integration support, reach out to us directly. We're happy to help with setup, testing, and debugging.