Skip to main content
Most integrations start by pushing your firm’s data into Metal: the companies you track, the deals in your pipeline, and the people you know. This guide shows how to create records and keep them current as your source systems change.

Pick an identifier strategy first

Before you write any data, decide how you’ll reconcile Metal records with your source system. Every resource has a Metal-assigned id, but you can attach your own identifiers so you never have to store a mapping table.
FieldUse it for
externalIdA single stable identifier you control (for example, a CRM record ID).
externalReferenceA structured reference to a source system when one ID isn’t enough.
Set externalId on create. It lets you fetch, update, and de-duplicate records later without tracking Metal’s id yourself. See the data model for the full field reference.

Create records

A company needs only a canonicalName. Supply a website when you have one — it dramatically improves enrichment accuracy.
curl -X POST https://api.metal.ai/v1/companies \
  -H "x-metal-client-id: $METAL_CLIENT_ID" \
  -H "x-metal-api-key: $METAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "canonicalName": "Acme Industrials",
    "website": "https://acme.example",
    "externalId": "crm-12345"
  }'
Deals point at a target company through companyId, and people link to a company through company:
curl -X POST https://api.metal.ai/v1/deals \
  -H "x-metal-client-id: $METAL_CLIENT_ID" \
  -H "x-metal-api-key: $METAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme — Project Forge",
    "companyId": "665f1c2a9b1e4a0012a3b4c5",
    "externalId": "crm-deal-987"
  }'

Keep records in sync

When a record changes in your system, update it in Metal. You can address a record by Metal id or by the externalId you set on create.
# Update by Metal id
curl -X PUT https://api.metal.ai/v1/companies/665f1c2a9b1e4a0012a3b4c5 \
  -H "x-metal-client-id: $METAL_CLIENT_ID" \
  -H "x-metal-api-key: $METAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "shortDescription": "Maker of factory automation hardware." }'

# Look up by your external id
curl "https://api.metal.ai/v1/companies/externalId=crm-12345" \
  -H "x-metal-client-id: $METAL_CLIENT_ID" \
  -H "x-metal-api-key: $METAL_API_KEY"

Build an upsert loop

For an ongoing sync, fetch by externalId, then create the record if it’s missing or update it if it exists. This keeps the job idempotent — safe to re-run without creating duplicates.
import os
import requests

BASE = "https://api.metal.ai/v1"
headers = {
    "x-metal-client-id": os.environ["METAL_CLIENT_ID"],
    "x-metal-api-key": os.environ["METAL_API_KEY"],
    "Content-Type": "application/json",
}

def upsert_company(record):
    ext = record["externalId"]
    existing = requests.get(f"{BASE}/companies/externalId={ext}", headers=headers)
    if existing.status_code == 200:
        company_id = existing.json()["data"]["id"]
        return requests.put(f"{BASE}/companies/{company_id}", headers=headers, json=record)
    return requests.post(f"{BASE}/companies", headers=headers, json=record)
Sync jobs make many calls in a row. Handle rate limits with backoff, and check errors before reading a response body.

Next steps

Enrich what you sync

Fill in firmographics and financials after creating records.

Organize into lists

Group synced records to work with them in bulk.