Build

Source packs, link types, attributes, scores, segments, dashboards, settings.

Source packs

The source packs this deployment accepts — the first call that proves your credential works.

curl -s "$ACKDB_URL/schemas/sources" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "data": [
    {
      "sourceType": "job",
      "contentSchema": {
        "event_type": "string",
        "full_name": "string",
        "linkedin_url": "string",
        "company": "string",
        "title": "string?",
        "title_category": "string?",
        "decision_maker_status": "boolean?",
        "change_type": "string?",
        "changed_at": "datetime?",
        "ended_at": "datetime?"
      },
      "identityLinkTypes": [
        "domain"
      ],
      "defaultTraits": [],
      "validEventTypes": [
        "job_change"
      ],
      "eventTypeField": "event_type",
      "eventTypePrefix": "job_",
      "eventMetadataFields": [
        "full_name",
        "linkedin_url",
        "title",
        "company",
        "decision_maker_status",
        "title_category",
        "change_type",
        "changed_at",
        "ended_at"
      ],
      "createdAt": "2026-07-01T00:00:00.000Z"
    }
  ]
}

List event types for a source

Parameters
sourceTyperequiredSource type (e.g.
curl -s "$ACKDB_URL/schemas/sources/{sourceType}/events" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "data": [
    {
      "sourceType": "stripe",
      "eventType": "invoice.paid",
      "description": "…",
      "category": "billing",
      "contentNature": "structured",
      "rationale": "…",
      "replacesEvents": [
        "…"
      ],
      "fields": {},
      "promotedMetadataFields": [
        "…"
      ],
      "traitHints": [
        {
          "traitKey": "…",
          "computeHint": "…",
          "updateStrategy": "always"
        }
      ],
      "ingestExample": {}
    }
  ],
  "meta": {
    "sourceType": "…",
    "displayName": "…",
    "description": "…",
    "version": "…",
    "totalEventTypes": 0
  }
}

Declare a custom source

Parameters
dryRunValidate without persisting.
Body
{
  "sourceType": "app_usage",
  "displayName": "App Usage",
  "description": "Daily product-usage rollups and per-user login activity from our application.",
  "version": "1.0.0",
  "queryingGuide": "Use usage.daily_rollup for trend/aggregate questions (DAU, credits burned). Use user.login for per-person engagement and seat activity.",
  "identityLinkTypes": [
    "domain",
    "app_account_id"
  ],
  "eventTypeField": "event_type",
  "eventTypePrefix": "app_usage_",
  "defaultContentNature": "structured",
  "allowCustomEventTypes": false,
  "defaultTraits": [
    {
      "traitKey": "app_usage_dau",
      "valueType": "number",
      "description": "Most recent daily active users for the account."
    },
    {
      "traitKey": "app_usage_credits_total",
      "valueType": "number",
      "description": "Lifetime credits consumed by the account."
    }
  ],
  "events": [
    {
      "eventType": "usage.daily_rollup",
      "description": "One row per account per day summarizing product usage.",
      "category": "usage",
      "contentNature": "structured",
      "eventScope": "entity",
      "fields": {
        "account_id": {
          "type": "string",
          "required": true,
          "description": "Application account identifier.",
          "computeHint": "Map from the rollup row's `account_id`.",
          "example": "acct_123"
        },
        "date": {
          "type": "datetime",
          "required": true,
          "description": "The UTC day this rollup covers.",
          "computeHint": "Map from the rollup row's `date` (start of day, UTC).",
          "example": "2026-06-15T00:00:00Z"
        },
        "sessions": {
          "type": "number",
          "required": true,
          "description": "Number of sessions on this day.",
          "computeHint": "Map from `metrics.sessions`.",
          "example": 84
        },
        "credits_consumed": {
          "type": "number",
          "required": true,
          "description": "Credits consumed on this day.",
          "computeHint": "Map from `metrics.credits_consumed`.",
          "example": 1200
        }
      },
      "promotedMetadataFields": [
        "account_id",
        "sessions",
        "credits_consumed"
      ],
      "ingestExample": {
        "source": "app_usage",
        "content": {
          "text": "Acme used 1200 credits across 84 sessions on 2026-06-15.",
          "metadata": {
            "event_type": "usage.daily_rollup",
            "account_id": "acct_123",
            "date": "2026-06-15T00:00:00Z",
            "sessions": 84,
            "credits_consumed": 1200
          }
        },
        "identityLinks": [
          {
            "externalIdType": "domain",
            "externalIdValue": "acme.com",
            "confidence": 1
          },
          {
            "externalIdType": "app_account_id",
            "externalIdValue": "acct_123",
            "confidence": 1
          }
        ],
        "traits": [
          {
            "traitKey": "app_usage_dau",
            "value": 84,
            "workflow": "app-usage-rollup",
            "confidence": 1
          }
        ],
        "timestamp": "2026-06-15T00:00:00Z"
      }
    },
    {
      "eventType": "user.login",
      "description": "A single user logged in to the application.",
      "category": "usage",
      "contentNature": "activity-signal",
      "eventScope": "person",
      "fields": {
        "account_id": {
          "type": "string",
          "required": true,
          "description": "Application account the user belongs to.",
          "computeHint": "Map from the login event's `account_id`.",
          "example": "acct_123"
        },
        "user_email": {
          "type": "string",
          "required": true,
          "description": "Email of the user who logged in.",
          "computeHint": "Map from `user.email`.",
          "example": "jane@acme.com"
        },
        "user_name": {
          "type": "string",
          "required": false,
          "description": "Display name of the user who logged in.",
          "computeHint": "Map from `user.name`.",
          "example": "Jane Doe"
        }
      },
      "promotedMetadataFields": [
        "account_id",
        "user_email"
      ],
      "contactMapping": {
        "role": "user",
        "nameField": "user_name",
        "emailField": "user_email",
        "externalIdField": "user_email",
        "externalIdType": "app_user_email"
      },
      "ingestExample": {
        "source": "app_usage",
        "content": {
          "text": "Jane Doe logged in.",
          "metadata": {
            "event_type": "user.login",
            "account_id": "acct_123",
            "user_email": "jane@acme.com",
            "user_name": "Jane Doe"
          }
        },
        "identityLinks": [
          {
            "externalIdType": "domain",
            "externalIdValue": "acme.com",
            "confidence": 1
          },
          {
            "externalIdType": "app_account_id",
            "externalIdValue": "acct_123",
            "confidence": 1
          }
        ],
        "traits": [],
        "timestamp": "2026-06-15T09:30:00Z"
      }
    }
  ]
}
curl -s -X POST "$ACKDB_URL/schemas/sources" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sourceType": "app_usage", "displayName": "App Usage", "description": "Daily product-usage rollups and per-user login activity from our application.", "version": "1.0.0", "queryingGuide": "Use usage.daily_rollup for trend/aggregate questions (DAU, credits burned). Use user.login for per-person engagement and seat activity.", "identityLinkTypes": [ "domain", "app_account_id" ], "eventTypeField": "event_type", "eventTypePrefix": "app_usage_", "defaultContentNature": "structured", "allowCustomEventTypes": false, "defaultTraits": [ { "traitKey": "app_usage_dau", "valueType": "number", "description": "Most recent daily active users for the account." }, { "traitKey": "app_usage_credits_total", "valueType": "number", "description": "Lifetime credits consumed by the account." } ], "events": [ { "eventType": "usage.daily_rollup", "description": "One row per account per day summarizing product usage.", "category": "usage", "contentNature": "structured", "eventScope": "entity", "fields": { "account_id": { "type": "string", "required": true, "description": "Application account identifier.", "computeHint": "Map from the rollup row's `account_id`.", "example": "acct_123" }, "date": { "type": "datetime", "required": true, "description": "The UTC day this rollup covers.", "computeHint": "Map from the rollup row's `date` (start of day, UTC).", "example": "2026-06-15T00:00:00Z" }, "sessions": { "type": "number", "required": true, "description": "Number of sessions on this day.", "computeHint": "Map from `metrics.sessions`.", "example": 84 }, "credits_consumed": { "type": "number", "required": true, "description": "Credits consumed on this day.", "computeHint": "Map from `metrics.credits_consumed`.", "example": 1200 } }, "promotedMetadataFields": [ "account_id", "sessions", "credits_consumed" ], "ingestExample": { "source": "app_usage", "content": { "text": "Acme used 1200 credits across 84 sessions on 2026-06-15.", "metadata": { "event_type": "usage.daily_rollup", "account_id": "acct_123", "date": "2026-06-15T00:00:00Z", "sessions": 84, "credits_consumed": 1200 } }, "identityLinks": [ { "externalIdType": "domain", "externalIdValue": "acme.com", "confidence": 1 }, { "externalIdType": "app_account_id", "externalIdValue": "acct_123", "confidence": 1 } ], "traits": [ { "traitKey": "app_usage_dau", "value": 84, "workflow": "app-usage-rollup", "confidence": 1 } ], "timestamp": "2026-06-15T00:00:00Z" } }, { "eventType": "user.login", "description": "A single user logged in to the application.", "category": "usage", "contentNature": "activity-signal", "eventScope": "person", "fields": { "account_id": { "type": "string", "required": true, "description": "Application account the user belongs to.", "computeHint": "Map from the login event's `account_id`.", "example": "acct_123" }, "user_email": { "type": "string", "required": true, "description": "Email of the user who logged in.", "computeHint": "Map from `user.email`.", "example": "jane@acme.com" }, "user_name": { "type": "string", "required": false, "description": "Display name of the user who logged in.", "computeHint": "Map from `user.name`.", "example": "Jane Doe" } }, "promotedMetadataFields": [ "account_id", "user_email" ], "contactMapping": { "role": "user", "nameField": "user_name", "emailField": "user_email", "externalIdField": "user_email", "externalIdType": "app_user_email" }, "ingestExample": { "source": "app_usage", "content": { "text": "Jane Doe logged in.", "metadata": { "event_type": "user.login", "account_id": "acct_123", "user_email": "jane@acme.com", "user_name": "Jane Doe" } }, "identityLinks": [ { "externalIdType": "domain", "externalIdValue": "acme.com", "confidence": 1 }, { "externalIdType": "app_account_id", "externalIdValue": "acct_123", "confidence": 1 } ], "traits": [], "timestamp": "2026-06-15T09:30:00Z" } } ] }'
Response · 200
{
  "data": {
    "valid": true,
    "dryRun": true,
    "sourceType": "app_usage",
    "eventTypes": [
      "usage.daily_rollup",
      "user.login"
    ]
  }
}

Edit a source (custom OR shipped pack)

Parameters
sourceTyperequiredSource type identifier (e.g.
Body
{
  "displayName": "App Usage (Production)",
  "queryingGuide": "Use usage.daily_rollup for trend questions, user.login for per-seat engagement.",
  "identityLinkTypes": [
    "domain",
    "app_account_id"
  ],
  "disabled": false
}
curl -s -X PUT "$ACKDB_URL/schemas/sources/{sourceType}" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "displayName": "App Usage (Production)", "queryingGuide": "Use usage.daily_rollup for trend questions, user.login for per-seat engagement.", "identityLinkTypes": [ "domain", "app_account_id" ], "disabled": false }'
Response · 200
{
  "data": {
    "source": {
      "sourceType": "slack",
      "contentSchema": {
        "channel_id": "string",
        "channel_name": "string",
        "message_text": "string",
        "user": "string",
        "thread_ts": "string?",
        "timestamp": "datetime"
      },
      "identityLinkTypes": [
        "slack_channel_id",
        "slack_user_id"
      ],
      "defaultTraits": [
        {
          "traitKey": "slack_message_count",
          "valueType": "number"
        }
      ],
      "validEventTypes": [
        "stripe_customer.subscription.created",
        "stripe_charge.succeeded",
        "stripe_invoice.paid",
        "stripe_charge.refunded"
      ],
      "eventTypeField": "event_type",
      "eventTypePrefix": "stripe_",
      "eventMetadataFields": [
        "amount_cents",
        "currency",
        "status",
        "customer_id"
      ],
      "createdAt": "2026-08-01T00:00:00Z"
    },
    "traitsCreated": 0
  }
}

Safely edit a source (guards data-orphaning removals)

Parameters
sourceTyperequiredSource type identifier (e.g.
Body
{
  "displayName": "App Usage (Production)",
  "queryingGuide": "Use usage.daily_rollup for trend questions, user.login for per-seat engagement."
}
curl -s -X PATCH "$ACKDB_URL/schemas/sources/{sourceType}" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "displayName": "App Usage (Production)", "queryingGuide": "Use usage.daily_rollup for trend questions, user.login for per-seat engagement." }'
Response · 200
{
  "data": {
    "source": {
      "sourceType": "slack",
      "contentSchema": {
        "channel_id": "string",
        "channel_name": "string",
        "message_text": "string",
        "user": "string",
        "thread_ts": "string?",
        "timestamp": "datetime"
      },
      "identityLinkTypes": [
        "slack_channel_id",
        "slack_user_id"
      ],
      "defaultTraits": [
        {
          "traitKey": "slack_message_count",
          "valueType": "number"
        }
      ],
      "validEventTypes": [
        "stripe_customer.subscription.created",
        "stripe_charge.succeeded",
        "stripe_invoice.paid",
        "stripe_charge.refunded"
      ],
      "eventTypeField": "event_type",
      "eventTypePrefix": "stripe_",
      "eventMetadataFields": [
        "amount_cents",
        "currency",
        "status",
        "customer_id"
      ],
      "createdAt": "2026-08-01T00:00:00Z"
    },
    "traitsCreated": 0
  }
}

Discover what may currently be edited on a source and its events

Parameters
sourceTyperequiredSource type (e.g.
curl -s "$ACKDB_URL/schemas/sources/{sourceType}/editability" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "data": {
    "sourceType": "stripe",
    "hasIngestedData": true,
    "userModified": false,
    "immutable": [
      "sourceType",
      "events[].eventType"
    ],
    "unsupported": [
      "delete an event type — no endpoint exists; delete the whole source instead"
    ],
    "events": [
      {
        "eventType": "invoice.paid",
        "hasStoredData": true,
        "userModified": false,
        "locked": [
          {
            "key": "eventType",
            "reason": "Event types cannot be renamed."
          },
          {
            "key": "fields[].type",
            "reason": "An existing field's type can never change."
          },
          {
            "key": "eventScope",
            "reason": "This event type has ingested data."
          }
        ]
      }
    ]
  }
}

Delete a custom source

Parameters
sourceTyperequiredCustom source type identifier (e.g.
curl -s -X DELETE "$ACKDB_URL/schemas/sources/{sourceType}" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "data": {
    "deleted": true,
    "sourceType": "app_usage"
  }
}

PUT replaces (omitted keys are deleted); PATCH preserves and refuses edits that strand stored data. sourceType and eventType never rename. Deleting needs the source disabled and empty of data. Guided path: Declare your own source.

Register an id scheme, so any source can address a company by it. Unregistered types are a 422 at push.

Body
{
  "key": "product_account_id",
  "description": "Our product org id, one per customer workspace"
}
curl -s -X POST "$ACKDB_URL/schemas/identity-link-types" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "key": "product_account_id", "description": "Our product org id, one per customer workspace" }'
Response · 201
{
  "data": {
    "typeKey": "duns_number",
    "description": "D-U-N-S business identifier",
    "builtIn": false,
    "createdAt": "2026-07-09T00:00:00.000Z",
    "updatedAt": "2026-07-09T00:00:00.000Z"
  }
}

Update a universal identity link type

Parameters
typeKeyrequiredThe link type key to update.
Body
{
  "description": "D-U-N-S Number — Dun & Bradstreet business identifier"
}
curl -s -X PATCH "$ACKDB_URL/schemas/identity-link-types/{typeKey}" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "description": "D-U-N-S Number — Dun & Bradstreet business identifier" }'
Response · 200
{
  "data": {
    "typeKey": "duns_number",
    "description": "D-U-N-S business identifier",
    "canMint": true,
    "builtIn": true,
    "createdAt": "2026-08-01T00:00:00Z",
    "updatedAt": "2026-08-01T00:00:00Z"
  }
}

Delete a universal identity link type

Parameters
typeKeyrequiredThe link type key to delete.
curl -s -X DELETE "$ACKDB_URL/schemas/identity-link-types/{typeKey}" \
  -H "Authorization: Bearer $ACKDB_API_KEY"

scope: entity (a company) or person (a durable human key). canMint: true lets an entity type create companies — for the domainless. domain is built-in and untouchable. Pushing a value of an unregistered type is a 422 — a typo can't mint a junk scheme.

Attributes

Your declared facts. Three write paths only — this API, console edit, the agent's gated tool. Ingest refuses them (422).

Create a custom attribute definition

Body
{
  "key": "…",
  "label": "…",
  "scope": "company",
  "type": "string",
  "description": "…",
  "allowedValues": [
    "…"
  ]
}
curl -s -X POST "$ACKDB_URL/attributes" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "key": "…", "label": "…", "scope": "company", "type": "string", "description": "…", "allowedValues": [ "…" ] }'
Response · 201
{
  "data": "…"
}

Edit an attribute's metadata, or migrate its scope

Parameters
keyrequiredAttribute key (snake_case).
Body
{
  "label": "…",
  "description": "…",
  "allowedValues": [
    "…"
  ],
  "scope": "person",
  "dryRun": true
}
curl -s -X PATCH "$ACKDB_URL/attributes/{key}" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "label": "…", "description": "…", "allowedValues": [ "…" ], "scope": "person", "dryRun": true }'
Response · 200
{
  "data": "…"
}

Delete a custom attribute

Parameters
keyrequiredAttribute key (snake_case).
curl -s -X DELETE "$ACKDB_URL/attributes/{key}" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "data": "…"
}

Set/clear attribute values on a company

Parameters
idrequiredCompany reference — an entity id (ULID) or a domain (e.g.
Body
{
  "values": {},
  "actor": "…"
}
curl -s -X PUT "$ACKDB_URL/entities/{id}/attributes" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "values": {}, "actor": "…" }'
Response · 200
{
  "data": "…"
}

Set/clear attribute values on a person

Parameters
idrequiredPerson reference — a person id (ULID), an email, or a LinkedIn URL.
Body
{
  "values": {},
  "actor": "…"
}
curl -s -X PUT "$ACKDB_URL/persons/{id}/attributes" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "values": {}, "actor": "…" }'
Response · 200
{
  "data": "…"
}

Standard attributes allow one edit: allowedValues — array order is funnel order, and shrinking past held values is a 409 with counts. Value writes are all-or-nothing; null clears. Fields and attributes.

Scores

What this server's score validator accepts

curl -s "$ACKDB_URL/scores/capabilities" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "grains": [
    "company"
  ],
  "scopes": {
    "segmentKinds": [
      "company"
    ],
    "derived": true
  },
  "aggregates": [
    {
      "value": "count",
      "grains": [
        "company"
      ],
      "scoring": [
        "bands"
      ],
      "requires": "sumField",
      "halfLife": true
    }
  ],
  "matchOps": [
    "eq"
  ],
  "normalizations": [
    "absolute"
  ],
  "percentilePopulations": [
    "all"
  ],
  "convergenceModes": [
    "sources"
  ],
  "eventValueMatching": "exact",
  "limits": {
    "criteria": 50,
    "groups": 10,
    "matchEntries": 0,
    "bands": 0,
    "labels": 0,
    "points": 100,
    "perUnitPoints": 0,
    "cap": 0,
    "windowDays": 3650,
    "convergenceWindowDays": 365,
    "convergenceSignals": 20
  }
}

Create a score definition

Body
{
  "scoreKey": "pql",
  "name": "PQL score",
  "description": "…",
  "grain": "company",
  "groups": [
    {
      "key": "fit",
      "weight": 0.4
    }
  ],
  "criteria": [
    {
      "group": "…",
      "field": "event:slack.message",
      "label": "…",
      "match": [
        {
          "op": "eq",
          "values": [
            "…"
          ],
          "points": 0
        }
      ],
      "bands": [
        {
          "gte": 0,
          "lt": 0,
          "points": 0
        }
      ],
      "agg": "count",
      "sumField": "…",
      "valueField": "employee_count",
      "windowDays": 0,
      "halfLifeDays": 0,
      "perUnitPoints": 0,
      "cap": 0,
      "filter": {
        "titleContains": [
          "…"
        ],
        "activeWithinDays": 0
      },
      "sources": [
        "…"
      ]
    }
  ],
  "normalization": "absolute",
  "percentilePopulation": "all",
  "labels": [
    {
      "gte": 0,
      "lt": 0,
      "label": "Excellent"
    }
  ],
  "scopeSegmentId": "…",
  "isPrimary": true,
  "enabled": true
}
curl -s -X POST "$ACKDB_URL/scores" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scoreKey": "pql", "name": "PQL score", "description": "…", "grain": "company", "groups": [ { "key": "fit", "weight": 0.4 } ], "criteria": [ { "group": "…", "field": "event:slack.message", "label": "…", "match": [ { "op": "eq", "values": [ "…" ], "points": 0 } ], "bands": [ { "gte": 0, "lt": 0, "points": 0 } ], "agg": "count", "sumField": "…", "valueField": "employee_count", "windowDays": 0, "halfLifeDays": 0, "perUnitPoints": 0, "cap": 0, "filter": { "titleContains": [ "…" ], "activeWithinDays": 0 }, "sources": [ "…" ] } ], "normalization": "absolute", "percentilePopulation": "all", "labels": [ { "gte": 0, "lt": 0, "label": "Excellent" } ], "scopeSegmentId": "…", "isPrimary": true, "enabled": true }'
Response · 201
{
  "scoreKey": "pql",
  "name": "PQL score",
  "description": "…",
  "grain": "company",
  "groups": [
    {
      "key": "fit",
      "weight": 0.4
    }
  ],
  "criteria": [
    {
      "group": "…",
      "field": "event:slack.message",
      "label": "…",
      "match": [
        {
          "op": "eq",
          "values": [],
          "points": 0
        }
      ],
      "bands": [
        {
          "gte": 0,
          "lt": 0,
          "points": 0
        }
      ],
      "agg": "count",
      "sumField": "…",
      "valueField": "employee_count",
      "windowDays": 0,
      "halfLifeDays": 0,
      "perUnitPoints": 0,
      "cap": 0,
      "filter": {
        "titleContains": [
          "…"
        ],
        "activeWithinDays": 0
      },
      "sources": [
        "…"
      ]
    }
  ],
  "normalization": "absolute",
  "percentilePopulation": "all",
  "labels": [
    {
      "gte": 0,
      "lt": 0,
      "label": "Excellent"
    }
  ],
  "scopeSegmentId": "…",
  "isPrimary": true,
  "enabled": true
}

Preview a DRAFT definition (unsaved)

Body
{
  "scoreKey": "pql",
  "name": "PQL score",
  "description": "…",
  "grain": "company",
  "groups": [
    {
      "key": "fit",
      "weight": 0.4
    }
  ],
  "criteria": [
    {
      "group": "…",
      "field": "event:slack.message",
      "label": "…",
      "match": [
        {
          "op": "eq",
          "values": [
            "…"
          ],
          "points": 0
        }
      ],
      "bands": [
        {
          "gte": 0,
          "lt": 0,
          "points": 0
        }
      ],
      "agg": "count",
      "sumField": "…",
      "valueField": "employee_count",
      "windowDays": 0,
      "halfLifeDays": 0,
      "perUnitPoints": 0,
      "cap": 0,
      "filter": {
        "titleContains": [
          "…"
        ],
        "activeWithinDays": 0
      },
      "sources": [
        "…"
      ]
    }
  ],
  "normalization": "absolute",
  "percentilePopulation": "all",
  "labels": [
    {
      "gte": 0,
      "lt": 0,
      "label": "Excellent"
    }
  ],
  "scopeSegmentId": "…",
  "isPrimary": true,
  "enabled": true
}
curl -s -X POST "$ACKDB_URL/scores/preview" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scoreKey": "pql", "name": "PQL score", "description": "…", "grain": "company", "groups": [ { "key": "fit", "weight": 0.4 } ], "criteria": [ { "group": "…", "field": "event:slack.message", "label": "…", "match": [ { "op": "eq", "values": [ "…" ], "points": 0 } ], "bands": [ { "gte": 0, "lt": 0, "points": 0 } ], "agg": "count", "sumField": "…", "valueField": "employee_count", "windowDays": 0, "halfLifeDays": 0, "perUnitPoints": 0, "cap": 0, "filter": { "titleContains": [ "…" ], "activeWithinDays": 0 }, "sources": [ "…" ] } ], "normalization": "absolute", "percentilePopulation": "all", "labels": [ { "gte": 0, "lt": 0, "label": "Excellent" } ], "scopeSegmentId": "…", "isPrimary": true, "enabled": true }'
Response · 200
{
  "buckets": [
    {
      "from": 0,
      "to": 0,
      "count": 0
    }
  ],
  "labels": [
    "…"
  ],
  "total": 0,
  "population": 0,
  "outOfScope": 0,
  "excluded": 0
}

Explain a company's score

Parameters
refrequiredEntity id or domain.
scoreKeyrequiredThe score definition's slug (immutable after create).
curl -s "$ACKDB_URL/entities/{ref}/scores/{scoreKey}/explain" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "scoreKey": "…",
  "grain": "company",
  "score": 82,
  "label": "Excellent",
  "normalization": "absolute",
  "scope": {
    "segmentId": "…",
    "segmentName": "…",
    "segmentKind": "company",
    "inScope": true
  },
  "groups": [
    {
      "key": "…",
      "weight": 0,
      "points": 0
    }
  ],
  "criteria": [
    {
      "field": "…",
      "labelText": "…",
      "group": "…",
      "matched": "…",
      "aggValue": 0,
      "asOf": "2026-08-01T00:00:00Z",
      "points": 0,
      "weighted": 0,
      "capped": true,
      "firedSources": [
        "…"
      ],
      "firedSignals": [
        "…"
      ]
    }
  ],
  "populationExcluded": true
}

Run the score time-series sweep

Body
{
  "scoreKey": "…",
  "epsilon": 0
}
curl -s -X POST "$ACKDB_URL/scores/snapshot" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scoreKey": "…", "epsilon": 0 }'
Response · 200
{
  "definitions": [
    {
      "scoreKey": "…",
      "grain": "company",
      "subjects": 0,
      "emitted": 0,
      "exited": 0,
      "skippedNoAnchor": 0
    }
  ],
  "totalEmitted": 0,
  "epsilon": 0
}

A company's score history

Parameters
refrequiredEntity id or domain.
scoreKeyrequiredThe score definition's slug (immutable after create).
fromWindow start (ISO).
toWindow end (ISO).
fillchanges (default): raw emissions.
curl -s "$ACKDB_URL/entities/{ref}/scores/{scoreKey}/history" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "scoreKey": "…",
  "grain": "company",
  "fill": "changes",
  "points": [
    {
      "date": "…",
      "score": 0,
      "label": "…"
    }
  ]
}

Build against capabilities, don't probe. 50 definitions, 20 enabled, per grain. Score responses are not data-enveloped; a key on both grains needs ?grain=. Scoring.

Segments

A segment is a saved live filter — membership computes at read time, never snapshotted. The field catalog and query grammar are on Read.

Create a segment

Body
{
  "name": "Active paying companies",
  "description": "Companies with a paid Stripe invoice",
  "entityKind": "company",
  "filter": {
    "type": "group",
    "op": "and",
    "children": [
      {
        "type": "group",
        "op": "and",
        "children": [
          {}
        ]
      }
    ]
  },
  "sort": [
    {
      "field": "event_count",
      "dir": "asc"
    }
  ],
  "columns": [
    {
      "field": "name",
      "frozen": true,
      "width": 200
    }
  ],
  "isDefault": false,
  "baseSegmentId": "01J9Z8Q3K2X7M4N5P6R7S8T9V0"
}
curl -s -X POST "$ACKDB_URL/observe/segments" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Active paying companies", "description": "Companies with a paid Stripe invoice", "entityKind": "company", "filter": { "type": "group", "op": "and", "children": [ { "type": "group", "op": "and", "children": [ {} ] } ] }, "sort": [ { "field": "event_count", "dir": "asc" } ], "columns": [ { "field": "name", "frozen": true, "width": 200 } ], "isDefault": false, "baseSegmentId": "01J9Z8Q3K2X7M4N5P6R7S8T9V0" }'
Response · 201
{
  "data": {
    "id": "01J9Z8Q3K2X7M4N5P6R7S8T9V0",
    "name": "Active paying companies",
    "description": "Companies with a paid Stripe invoice",
    "entityKind": "company",
    "filter": {
      "type": "group",
      "op": "and",
      "children": [
        {
          "type": "group",
          "op": "and",
          "children": []
        }
      ]
    },
    "sort": [
      {
        "field": "event_count",
        "dir": "asc"
      }
    ],
    "columns": [
      {
        "field": "name",
        "frozen": true,
        "width": 200
      }
    ],
    "isDefault": false,
    "baseSegmentId": null,
    "ownerEmail": "rep@acme.com",
    "access": "owner",
    "createdAt": "2026-08-01T00:00:00Z",
    "updatedAt": "2026-08-01T00:00:00Z"
  }
}

Get segment results

Parameters
idrequired
grainRender grain.
extraFilterURL-encoded JSON FilterGroup, authored in the RENDER (target) grain's vocabulary, ANDed on top of the pivoted set ('filter on top' - e.g.
columnsURL-encoded JSON array of column projections ([{ field, frozen?, width? }, …]) in the RENDER (target) grain's vocabulary, used to project the pivot rows instea…
sortURL-encoded JSON array of sort entries ([{ field, dir: 'asc'|'desc' }, …]) in the RENDER (target) grain's vocabulary — a TRANSIENT sort override (header-click …
limit50
offset0
curl -s "$ACKDB_URL/observe/segments/{id}/results?limit=50&offset=0" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "data": [
    {
      "entityId": "…",
      "name": "…",
      "domain": "…"
    }
  ],
  "pagination": {
    "total": 150,
    "limit": 50,
    "offset": 0,
    "totalIsLowerBound": true
  }
}

Replace a segment's member shares

Parameters
idrequired
Body
{
  "shares": [
    {
      "memberId": "01J9Z8Q3K2X7M4N5P6R7S8T9V0",
      "role": "edit"
    }
  ]
}
curl -s -X PUT "$ACKDB_URL/observe/segments/{id}/shares" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "shares": [ { "memberId": "01J9Z8Q3K2X7M4N5P6R7S8T9V0", "role": "edit" } ] }'
Response · 200
{
  "data": [
    {
      "memberId": "01J9Z8Q3K2X7M4N5P6R7S8T9V0",
      "role": "edit",
      "name": "Jordan Rep",
      "email": "jordan@acme.com",
      "createdAt": "2026-08-01T00:00:00Z"
    }
  ]
}

Segment change feed (poll)

Parameters
idrequired
sinceCursor - return rows with seq > since.
curl -s -X POST "$ACKDB_URL/observe/segments/{id}/changes" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "segmentId": "…",
  "filterHash": "…",
  "maxSeq": 0,
  "minRetainedSeq": 0,
  "changes": [
    {
      "seq": 0,
      "entityId": "…",
      "kind": "enter",
      "at": "2026-08-01T00:00:00Z"
    }
  ],
  "hasMore": true,
  "nextSince": 0,
  "bootstrapped": true,
  "reconcile": true,
  "reason": "cursor_ahead"
}

Segment live member ids (keyset)

Parameters
idrequired
afterKeyset cursor - return member ids strictly greater than this.
limitPage size (default 1000, max 5000).
curl -s "$ACKDB_URL/observe/segments/{id}/member-ids" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "segmentId": "…",
  "entityIds": [
    "…"
  ],
  "nextCursor": "…",
  "hasMore": true
}

The changes feed is at-least-once with a cursor: seed with member-ids, then poll. 409 LOCK_BUSY retry shortly; 410 CURSOR_EXPIRED re-seed. Exports and the change feed.

Dashboards

Create a dashboard

Body
{
  "name": "…",
  "description": "…",
  "panels": [
    {
      "key": "…",
      "title": "…",
      "type": "kpi",
      "segmentId": "…",
      "spec": {
        "agg": "count",
        "field": "…"
      },
      "viz": "…",
      "degraded": true,
      "degradedReason": "segment deleted"
    }
  ],
  "artifact": {
    "html": "…",
    "queries": [
      {
        "key": "…",
        "sql": "…"
      }
    ]
  },
  "layout": "…"
}
curl -s -X POST "$ACKDB_URL/observe/dashboards" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "…", "description": "…", "panels": [ { "key": "…", "title": "…", "type": "kpi", "segmentId": "…", "spec": { "agg": "count", "field": "…" }, "viz": "…", "degraded": true, "degradedReason": "segment deleted" } ], "artifact": { "html": "…", "queries": [ { "key": "…", "sql": "…" } ] }, "layout": "…" }'
Response · 201
{
  "data": {
    "id": "…",
    "name": "…",
    "description": "…",
    "ownerEmail": "…",
    "access": "owner",
    "panels": [
      {
        "key": "…",
        "title": "…",
        "type": "kpi",
        "segmentId": "…",
        "spec": {
          "agg": "count",
          "field": "…"
        },
        "viz": "…",
        "degraded": true,
        "degradedReason": "segment deleted"
      }
    ],
    "artifact": {
      "html": "…",
      "queries": [
        {
          "key": "…",
          "sql": "…"
        }
      ]
    },
    "layout": "…",
    "createdAt": "2026-08-01T00:00:00Z",
    "updatedAt": "2026-08-01T00:00:00Z"
  }
}

Preview one draft panel

Body
{
  "panel": {
    "key": "…",
    "title": "…",
    "type": "kpi",
    "segmentId": "…",
    "spec": {
      "agg": "count",
      "field": "…"
    },
    "viz": "…",
    "degraded": true,
    "degradedReason": "segment deleted"
  }
}
curl -s -X POST "$ACKDB_URL/observe/dashboards/preview" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "panel": { "key": "…", "title": "…", "type": "kpi", "segmentId": "…", "spec": { "agg": "count", "field": "…" }, "viz": "…", "degraded": true, "degradedReason": "segment deleted" } }'
Response · 200
{
  "data": {
    "value": 0
  }
}

Run one panel

Parameters
idrequiredDashboard id (ULID).
panelrequiredThe panel key.
curl -s "$ACKDB_URL/observe/dashboards/{id}/data" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "data": {
    "value": 0
  }
}

Config only — every read re-runs live. Six panel types: kpi, breakdown, timeseries, table, feed, sql. Data reads always answer 200 with one arm: data, degraded, or a panel-scoped error. Dashboards.

Settings

Set internal domains

Body
{
  "domains": [
    "floqer.com",
    "floqer.io"
  ]
}
curl -s -X PUT "$ACKDB_URL/config/internal-domains" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domains": [ "floqer.com", "floqer.io" ] }'
Response · 200
{
  "domains": [
    "…"
  ]
}

Add internal user

Body
{
  "email": "sarah@gmail.com",
  "name": "Sarah Chen",
  "sourceIds": [
    {
      "source": "…",
      "externalIdType": "…",
      "externalIdValue": "…"
    }
  ],
  "notes": "Contractor, works on billing"
}
curl -s -X POST "$ACKDB_URL/config/internal-users" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "sarah@gmail.com", "name": "Sarah Chen", "sourceIds": [ { "source": "…", "externalIdType": "…", "externalIdValue": "…" } ], "notes": "Contractor, works on billing" }'
Response · 201
{
  "id": "…",
  "email": "…",
  "name": "…",
  "sourceIds": [
    {
      "source": "…",
      "externalIdType": "…",
      "externalIdValue": "…"
    }
  ],
  "notes": "…",
  "createdAt": "2026-08-01T00:00:00Z"
}

Get agent LLM config

curl -s "$ACKDB_URL/config/agent" \
  -H "Authorization: Bearer $ACKDB_API_KEY"
Response · 200
{
  "provider": "anthropic",
  "model": "claude-opus-4-8",
  "apiModel": "…",
  "baseUrl": "…",
  "source": "custom",
  "apiKey": {
    "configured": true,
    "source": "custom",
    "masked": "sk-ant…abcd"
  },
  "apiKeys": {},
  "providers": [
    {}
  ]
}

Set agent LLM config

Body
{
  "provider": "anthropic",
  "model": "claude-opus-4-8",
  "baseUrl": "…",
  "apiKey": "…",
  "validate": true
}
curl -s -X PUT "$ACKDB_URL/config/agent" \
  -H "Authorization: Bearer $ACKDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "provider": "anthropic", "model": "claude-opus-4-8", "baseUrl": "…", "apiKey": "…", "validate": true }'

Config takes effect on the next call — no restart. Keys are write-only and saves are live-validated. Responses are not data-enveloped. Settings.