Synchronise your customer data

Cycle allow you to synchronise your customer data at company level.

Initial import

If you're just getting started, you’ll want to import your existing company and user data into Cycle. Here’s how to format your CSV for import:

companyName,name,email,customId,attioId,zendeskId,hubspotId,intercomId,pipedriveId,snowflakeId,salesforceId
Acme,John Doe,[email protected],acme-001,a123,zendesk_456,hubspot_789,int_001,pipe_999,sf_acme_1,sf_001
Acme,Jane Doe,[email protected],acme-001,a123,zendesk_456,hubspot_789,int_001,pipe_999,sf_acme_1,sf_001
Wayne Enterprises,Bruce Wayne,[email protected],wayne-001,a555,zendesk_789,hubspot_321,int_003,pipe_777,sf_wayne_1,sf_003
Airbnb,Main contact,[email protected],airbnb-001,a777,zendesk_000,hubspot_000,int_004,pipe_666,sf_airbnb_1,sf_004
Field name
Description

companyName

The name of the company

name

The full name of the person (Or `Main contact`)

email

Their email (or `[email protected]`)

customId (optional)

ID of your choice

attioId (optional)

ID of your Attio CRM

zendeskId (optional)

ID of your Zendesk CRM

hubspotId (optional)

ID of your HubSpot CRM

intercomId (optional)

ID of your Intercom CRM

pipedrive (optional)

ID of your Pipedrive CRM

snowflakeId (optional)

ID of your Snowflake CRM

Note that every row correspond to people granularity, so if you do not have any human contact but only a company, as the last row in the above example, use a Main contact approach.

IDs allow you later to match company via ID. So they are attached to Company and not people


Once your CSV is ready, you can upload it using Cycle’s GraphQL API.

Here’s the mutation to use:

graphqlCopyEditmutation importCustomersFromCSV($file: Upload!, $workspaceId: ID!) {
  importCustomersFromCSV(csvFile: $file, productId: $workspaceId)
}

Examples

curl https://api.product.cycle.app/graphql \
  -X POST \
  -H "Authorization: Bearer YOUR_CYCLE_API_KEY" \
  -F operations='{
    "query": "mutation importCustomersFromCSV($file: Upload!, $workspaceId: ID!) { importCustomersFromCSV(csvFile: $file, productId: $workspaceId) }",
    "variables": { "file": null, "workspaceId": "YOUR_WORKSPACE_ID" }
  }' \
  -F map='{ "0": ["variables.file"] }' \
  -F 0=@your_file.csv

Real-time sync with your CRM

Once your companies are in Cycle, you’ll want to keep them in sync with your CRM

For instance: When something changes in your CRM e.g. a company stage changes to “Closed Won”

Syncing updates from CRM to Cycle

Let’s say you just updated Acme’s stage to Closed Won in your CRM. You now want to reflect that change in Cycle.

To do that, you need to 👇

Step 1: Fetch the attribute definition ID

Before updating any company attribute, you need to retrieve the definition ID of the attribute (e.g. Stage) 👉 In this case we assume Stage is a Select value, so you will also need the value id

GraphQL query:

query workspaceBySlug($slug: DefaultString!) {
    getProductBySlug(slug: $slug) {
        id
        name
        slug
        companyAttributeDefinitions(
            pagination: {
                size: 100,
                where: {
                    cursor: "",
                    direction: AFTER
                }
            }
        ) {
            pageInfo {
                endCursor
                hasNextPage
            }
            edges {
                node {
                    __typename
                    ... on AttributeTextDefinition {
                        id
                        name
                    }
                    ... on AttributeNumberDefinition {
                        id
                        name
                    }
                    ... on AttributeCheckboxDefinition {
                        id
                        name
                    }
                    ... on AttributeSingleSelectDefinition {
                        id
                        name
                        valuesV2(pagination: {
                            size: 100,
                            where: {
                                cursor: "",
                                direction: AFTER
                            }
                        }) {
                            edges {
                                node {
                                    id
                                    value
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

This will return a list of all attribute definitions available in your workspace.

Find the one named Stage and copy its id (and the corresponding valueId if it's a select field).

Step 2: Update the company in Cycle

Once you have the attributeDefinitionId and (if needed) the valueId, use the following mutation:

updateCompanyAttributeValue(
  $companyId: ID!
  $attributeDefinitionId: ID!
  $value: CompanyAttributeValueInput!
) {
  updateCompanyAttributeValue(
    companyId: $companyId
    attributeDefinitionId: $attributeDefinitionId
    value: $value
  ) {
    __typename
    ... on CompanyAttributeCheckbox {
      id
      definition {
        id
        __typename
      }
      value {
        id
        valueCheckbox: value
      }
    }
    ... on CompanyAttributeText {
      id
      definition {
        id
        __typename
      }
      value {
        id
        valueText: value
      }
    }
    ... on CompanyAttributeSingleSelect {
      id
      definition {
        id
        __typename
      }
      value {
        id
        valueSelect: value
      }
    }
  }
}

Examples

curl https://api.product.cycle.app/graphql \
  -X POST \
  -H "Authorization: Bearer YOUR_CYCLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation updateCompanyAttributeValue($companyId: ID!, $attributeDefinitionId: ID!, $value: CompanyAttributeValueInput!) { updateCompanyAttributeValue(companyId: $companyId, attributeDefinitionId: $attributeDefinitionId, value: $value) { __typename ... on CompanyAttributeSingleSelect { id definition { id __typename } value { id valueSelect: value } } } }",
    "variables": {
      "companyId": "company-id-of-acme",
      "attributeDefinitionId": "definition-id-of-stage",
      "value": {
        "select": "value-id-for-closed-won"
      }
    }
  }'

Create new attributes

If you need to add an attribute that does not exist yet, you first need to create it. So by using the following mutation, you are adding a "column" to your Company table so you will be able to filter on it in your dashboard.

curl https://api.product.cycle.app/graphql \
  -X POST \
  -H "Authorization: Bearer YOUR_CYCLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "
      mutation scalarTextAttribute($workspaceId: ID!, $name: String!) {
        addNewCompanyAttribute(
          input: {
            productId: $workspaceId
            name: $name
            color: \"a\"
            type: { scalar: { type: TEXT } }
          }
        ) {
          __typename
        }
      }
    ",
    "variables": {
      "workspaceId": "YOUR_WORKSPACE_ID",
      "name": "Churn reason"
    }
  }'

Get all existing attributes

The easiest way to get the current attributes is to fetch at the product level and use the ID you will retrieve.

curl https://api.product.cycle.app/graphql \
  -X POST \
  -H "Authorization: Bearer YOUR_CYCLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "
      query workspaceBySlug($slug: DefaultString!) {
        getProductBySlug(slug: $slug) {
          id
          name
          slug
          companyAttributeDefinitions(
            pagination: {
              size: 100,
              where: {
                cursor: \"\",
                direction: AFTER
              }
            }
          ) {
            pageInfo {
              endCursor
              hasNextPage
            }
            edges {
              node {
                __typename
                ... on AttributeTextDefinition {
                  id
                  name
                }
                ... on AttributeNumberDefinition {
                  id
                  name
                }
                ... on AttributeCheckboxDefinition {
                  id
                  name
                }
                ... on AttributeSingleSelectDefinition {
                  id
                  name
                  valuesV2(pagination: {
                    size: 100,
                    where: {
                      cursor: \"\",
                      direction: AFTER
                    }
                  }) {
                    edges {
                      node {
                        id
                        value
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    ",
    "variables": {
      "slug": "YOUR_WORKSPACE_SLUG"
    }
  }'

Daily synchronisation

A very typical way of keeping your data in-sync would be to have a cron job who run every day and update in bulk all your companies that changed during the last day.

  • Fetch companies from your database that were updated in the last 24 hours

  • Generate a CSV with those companies and the latest values

  • Use the mutation below to update them in bulk in Cycle

mutation updateCompanyAttributeValuesFromCSV($file: Upload!, $workspaceId: ID!) {
  updateCompanyAttributeValuesFromCSV(csvFile: $file, productId: $workspaceId)
}

⚠️ You must define which column to use as the unique company identifier during the update. It can be one of these: companyName, customId, attioId, zendeskId, hubspotId, intercomId, pipedriveId, snowflakeId, salesforceId

Cycle will use this column to match each row with an existing company in your workspace.

CSV format

Here’s an example of how your update CSV could look:

companyName	customId	attioId	zendeskId	hubspotId	intercomId	pipedriveId	snowflakeId	salesforceId	arr	numberOfEmployees	country	leadStatus	industry	closedDate	custom attribute
Acme			...			...			...			...			...			...			...			250000	50	France	Closed	HR	1678670383	...

Each column corresponds to an attribute in Cycle. You can update as many fields as you want in one go — just make sure the header names match exactly with the attribute names defined in your workspace (case-sensitive!).

Once your CSV is ready, upload it via the updateCompanyAttributeValuesFromCSV mutation.

Last updated

Was this helpful?