Appnigma
SDKRead and write data

Last updated on October 23, 2026

CRM data

Read an end customer's contacts, companies and deals in one shape, whichever CRM they use.

What crm does

crm.contacts, crm.companies and crm.deals read an end customer's CRM in one shape, whichever CRM they use. Each has list and get.

const page = await appnigma.crm.contacts.list({ endCustomerId: "lawfirm-123", platform: "attio", limit: 50 });
for (const contact of page.records) console.log(contact.fullName, contact.emails[0]?.value);

// The next page, while there is one.
if (page.next) {
  await appnigma.crm.contacts.list({ endCustomerId: "lawfirm-123", platform: "attio", cursor: page.next });
}

const { record } = await appnigma.crm.deals.get({ endCustomerId: "lawfirm-123", platform: "hubspot", id: "1234" });
console.log(record.name, record.amount, record.currency, record.status);
page = client.crm.contacts.list(end_customer_id: "lawfirm-123", platform: "attio", limit: 50)
page[:records].each { |contact| puts "#{contact[:full_name]} #{contact[:emails].first&.dig(:value)}" }

# The next page, while there is one.
client.crm.contacts.list(end_customer_id: "lawfirm-123", platform: "attio", cursor: page[:next]) if page[:next]

deal = client.crm.deals.get(end_customer_id: "lawfirm-123", platform: "hubspot", id: "1234")[:record]
puts "#{deal[:name]} #{deal[:amount]} #{deal[:currency]} #{deal[:status]}"
page = client.crm.contacts.list(end_customer_id="lawfirm-123", platform="attio", limit=50)
for contact in page["records"]:
    email = contact["emails"][0]["value"] if contact["emails"] else None
    print(contact["full_name"], email)

# The next page, while there is one.
if page["next"]:
    client.crm.contacts.list(end_customer_id="lawfirm-123", platform="attio", cursor=page["next"])

deal = client.crm.deals.get(end_customer_id="lawfirm-123", platform="hubspot", id="1234")["record"]
print(deal["name"], deal["amount"], deal["currency"], deal["status"])

Read a page: list

Names are shown as in TypeScript. Ruby and Python use the same names in snake case: end_customer_id.

endCustomerIdstringrequired

Your own id for your customer. 1 to 100 characters of letters, digits, dot, dash or underscore.

platformstringrequired

The platform, such as hubspot or attio. It must be switched on for your company.

limitnumberoptionaldefault: 100

How many records in one page, from 1 to 100.

cursorstringoptional

The next value from the previous page. Leave it out for the first page.

recordsarray

The records in this page, in the shapes below.

nextstring or null

Pass it as cursor for the next page. Empty on the last page.

Read one record: get

endCustomerIdstringrequired

Your own id for your customer.

platformstringrequired

The platform, such as hubspot.

idstringrequired

The record's id in the CRM.

recordobject

The record, in the shape below.

The shapes

Every field is always there: a value the CRM does not have is empty (null in TypeScript, nil in Ruby, None in Python), never left out.

Field names are shown as in TypeScript. In Ruby and Python they are the same in snake case: full_name, created_at, custom_fields, and so on.

ObjectFields
Every recordid, platform, createdAt, updatedAt, customFields, and raw, the record exactly as the CRM sent it
ContactfirstName, lastName, fullName, emails, phones (the primary one first), companyId, ownerId
Companyname, domain, ownerId
Dealname, amount, currency, status (open, won or lost), stage, pipeline, probability, closeDate, closedAt, companyId, ownerId

Some fields hold more than one value:

FieldShape
emailsA list. Each has value, type (work, personal, other or empty) and primary (true or false).
phonesA list. Each has value, type (work, mobile, home, fax, other or empty) and primary.
stage, pipelineThe CRM's own stage or pipeline: its id, and its label when the CRM has one.
customFieldsThe CRM's own fields, keyed by the CRM's field names. Each has a label and a value.

When it fails

  • DATA_TYPE_NOT_AVAILABLE: the platform has no unified data yet for that object. Reach it with request instead. In TypeScript this is a SdkNotAvailableError, in Ruby an Appnigma::NotAvailableError, in Python a NotAvailableError.
  • RECORD_NOT_FOUND: no record with that id. In TypeScript this is a SdkNotFoundError, in Ruby an Appnigma::NotFoundError, in Python a NotFoundError.

Reads are tried again only when that is safe, up to three times by default. See Retries and time limits. Every code is on Errors.

On this page