orakel
Docs navigation

Canonical

Attio

Push enriched Orakel company records into Attio CRM records.

Updated 2026-04-21

Overview

Attio is a records-first CRM. Orakel pushes company records (firmographics, financials, roles, domains, technographics, TBR licenses) into an Attio workspace, upserting on org_number and falling back to domain match.

The integration is push-based: create a Destination of type attio with an Attio API token, then call POST /api/push/:destinationName with a list of Norwegian org numbers. Destination config is encrypted at rest (AES-256-GCM).

There is a separate webhook path (POST /api/webhooks/attio) that triggers enrichment when a record is created or updated inside Attio — see Gotchas.

Setup

  1. Create an Attio API token — Attio Settings → Developers → Create access token. Scope it to your workspace with read/write on the companies object.
  2. Create the destination:
    curl -X POST https://orakel.cloud/api/destinations \
      -H "Authorization: Bearer $ORAKEL_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "attio-prod",
        "type": "attio",
        "config": {
          "apiKey": "sk_live_...",
          "fieldMappings": {
            "naceDescription1": "nace_description",
            "revenue": "revenue"
          }
        }
      }'
  3. Trigger a push:
    curl -X POST https://orakel.cloud/api/push/attio-prod \
      -H "Authorization: Bearer $ORAKEL_KEY" \
      -H "Content-Type: application/json" \
      -d '{"orgNumbers": ["923609016"]}'

Field mapping

Two categories of fields are written to Attio:

Built-in Attio slugs (always written, no mapping required)

Orakel field Attio slug Shape
foundingDate foundation_date [{ value: "YYYY-MM-DD" }]
businessAddress* primary_location [{ line_1, locality, region, postcode, country_code, ... }]
employeeCount employee_range [{ option: "1-10" | "11-50" | "51-250" | ... }]
linkedinHandle linkedin [{ value: "https://linkedin.com/company/<handle>" }]
facebookHandle facebook [{ value: "https://facebook.com/<handle>" }]
instagramHandle instagram [{ value: "https://instagram.com/<handle>" }]
twitterHandle twitter [{ value: "https://x.com/<handle>" }]

Custom slugs (written only if listed in config.fieldMappings)

Keys on the left are Orakel field names; values on the right are your workspace's Attio slugs. The adapter exposes: orgNumber, country, name, orgFormCode, naceCode1, naceDescription1, employeeCount, businessAddressMuni, businessAddressMuniNo, countyCode, website, phone, sectorDescription, isBankrupt, isBeingDissolved, parentOrgNumber, primaryDomain, domainConfidence, enrichedDomains, linkedinHandle, facebookHandle, instagramHandle, twitterHandle, technologies, revenue, netResult, operatingResult, totalAssets, totalEquity, totalDebt, ceo, boardChair, boardMembers, auditor. If the company has a TBR skjenkebevilling, the adapter also exposes licenseType, licenseVenueName, licenseMunicipality, licenseValidFrom, licenseValidTo, hasSpirits, hasWine, hasBeer, licenseCount.

Mapping any field to Attio's built-in domains slug is handled specially: strings get stripped and wrapped, arrays pass through, and enrichedDomains is preferred over website when richer.

Configuration

{
  "apiKey": "sk_live_...",
  "fieldMappings": {
    "orgNumber": "org_number",
    "revenue": "revenue",
    "ceo": "ceo_name",
    "primaryDomain": "domains"
  }
}
  • apiKey — Attio access token. Required.
  • fieldMappings — map of Orakel field → Attio slug. Optional; omit to use only the built-in slugs above.

Push behavior

  • Matching: search for an existing record by org_number. If none, fall back to domains. If still none, create.
  • On match: PATCH the existing record. The name attribute is stripped from the update payload to preserve brand names.
  • On no match: POST a new record.
  • Per-company result is tallied into created, updated, failed counts, returned by POST /api/push/:destinationName.

Gotchas

  • Financials: use Currency type in Attio for revenue, netResult, operatingResult, totalAssets, totalEquity, totalDebt. Text type will round-trip to string and break sorting.
  • Built-in fields use array-of-objects shape: [{ value: "..." }] for text/date, [{ option: "..." }] for select, [{ line_1, ... }] for location. The adapter handles this; if you copy the mapping elsewhere, respect the shape.
  • Webhook envelope: Attio sends webhooks wrapped in { webhook_id, events: [...] }, not flat single events. The Orakel webhook handler iterates events[] and dispatches per entry.
  • No webhook delivery history in Attio API: check Attio Settings → Developers → Webhooks for failures.
  • Token scope: a workspace-scoped token cannot reach objects in other workspaces. One destination per workspace.