Universal CRM API

Read and write existing data in your users' CRMs

Xkit's Universal CRM API enables your app to interact with data in your user's CRM in a consistent way, regardless of which CRM they use or what customizations they have applied.

CRM configurations are as unique as the businesses they power, so user-driven configuration is a must for CRM integrations.

The Universal CRM API allows your app to:

  • Read data from the user's CRM in a consistent format
  • Get notified of changes to data in the user's CRM
  • Add and change data in the user's CRM in a consistent way

The Universal CRM API allows your users to:

  • Configure the objects and fields that best map to what your app needs
  • Control what data is exposed to your app
  • Manage how changes happen to their data

CRM Objects

CRM Objects are objects that already exist in your users' CRM and are relevant to your application.

You can think of these as your app's view of a generic CRM, which your user will then map to their actual CRM.

Here's an example of a user mapping a CRM object to an actual object in their CRM:

Selecting an object in CRM Link

An example CRM Object for an e-signature SaaS App would be an "Opportunity", which might be linked to an Opportunity, a Deal, or some other object based on the specific user's CRM.

For each CRM Object, you'll define fields that you want to read from the CRM, and events that you can invoke to find and change data in the CRM.

Create in Developer Portal

While logged into the Xkit Developer Portal, click on "CRM Objects" in the menu.

Click "Create" and add the requested information:

  • Slug: the name of your CRM Object as it appears in the Xkit API, e.g. opportunity
  • Name: the name of the CRM Object as it appears to users during mapping, e.g. Opportunity
  • Description: a description of the CRM Object to help your users determine the right object in their CRM to map to it, e.g,: "Acme associates documents with Opportunities or Deals in your CRM and pre-populates document templates based on data available in the Opportunity"

After you've installed CRM Link, add an empty configuration object to the objects property of the options object of linkCRM of the format: { fields: {}, events: {} }.

For our example with an opportunity CRM object, that looks like this:

await linkCRM('example.xkit.co', token, {
  objects: {
    opportunity: {
      fields: {},
      events: {}
    }
  }
})

In upcoming sections, we'll add fields and events.

Read data

In order to read data from the CRM, your app needs to declare the fields that are relevant to it, which the user then maps to the actual data in their CRM.

Once configured by the user, all responses from Xkit for a CRM record for this CRM Object will be mapped according to the user's preferences.

To define fields for mapping, you pass them to the fields object in CRM Link.

Here's what the end user will experience when mapping the fields that you pass:

Mappping fields for reading using CRM Link

For example, your e-signature app may want a document_name, which the user could map to the Opportunity's Name property in Salesforce.

These fields will only apply for the CRM connection made for that specific invocation of CRM Link. Your app is responsible for managing differences in mappings between users or updates to internal schemas.

Because there are no guarantees about the structure of any given user's CRM, or even the existence of data in a mapped field, your application should always gracefully handle null values in any of your requested mapped fields.

User-defined fields

Many applications allow users to provide arbitrary data to the application. To allow your users to provide arbitrary data via their CRM, use an object-type field. An object-type field will allow your users to either:

  • Create custom fields with user-defined names and values as children of the field
  • Map the field to an object field that exists in the user's CRM

Format and Example

The fields are an object with the following structure:

  • Key: this is the slug or API name of the field, e.g. name
  • Value: an Xkit-flavored JSON schema description of the value of the field, e.g. { type: 'string' }
    • Include a label to have a user-facing title for this field
    • Include a description to help users map this field
await linkCRM(token, {
  objects: {
    opportunity: {
      fields: {
        document_name: {
          type: "string",
          label: "Document Name",
          description: "The name of the document to pre-populate during document creation."
        },
        document_tags: {
          type: "object",
          label: "Document Tags",
          description: "Tags to apply to the document during creation"
        }
      }
    }
  }
})

Read data on demand

The Xkit API exposes two endpoints to read data on demand:

  • Get CRM Record
  • Get CRM Record Batch

In addition to these endpoints, the mapping the user defines will be used to return all records for all interactions with the Xkit CRM API.

Here's an example request/response for Get CRM Record:

Request

GET /api/crm/1234/objects/opportunity/Opportunity:09876/mapping HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

Response

200 OK
Content-Type: application/json

{
  "record": {
    "type": "opportunity",
    "id": "Opportunity:09876",
    "data": {
      "document_name": "Apple Opportunity Sales Contract",
      "document_tags": {}
    }
  }
}

Find data

In order to find relevant data in the user's CRM, you'll need to declare an event during CRM Link which you can later invoke using the Invoke Event endpoint.

Rather than directly searching through the user's CRM (which has an arbitrary and unknown structure), you'll instead tell the user the data that you need and they'll create a search query unique to their CRM during CRM link to expose that data to you.

Here's how that looks from the user's perspective:

Handling a search event in CRM Link

Define search event

To define a search event, you'll pass an object to the events object of your CRM Object's definition in your CRM Link invocation with the following structure:

  • Key: this is the slug of the event, which you'll use when invoking the event in the Xkit API
  • Value: an object with the following structure
    • type: search
    • name: the user-facing name of the event, e.g. "Find Opportunities in Proposal"
    • description: the user-facing description of the event and how the user should handle it, e.g. "Opportunities or Deals in your CRM that are in a proposal stage and are available to have a document generated for them."
    • payloadSchema: Xkit-flavored JSON describing the schema of the payload you'll provide when invoking the event
await linkCRM(token, {
  objects: {
    opportunity: {
      events: {
        find_proposal_opportunities: {
          type: "search",
          name: "Find Opportunities in Proposal",
          description: "Opportunities or Deals in your CRM that are in a proposal stage and are available to have a document generated for them.",
          payloadSchema: {
            account_id: {
              label: "Account ID",
              description: "ID of the Account associated with the opportunities",
              type: "string"
            }
          }
        }
      }
    }
  }
})

Invoke search event

Invoke the search event by using the Invoke Event endpoint. Page through the returned records to retrieve all of the found data, which will be mapped according to the fields defined in CRM Link

Here's an example request and response for invoking a search event for a CRM object with the slug opportunity and an event with the slug find_proposal_opportunities:

Request

POST /api/crm/1234/objects/opportunity/events/find_proposal_opportunities HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

{
  "payload": {
    "account_id": "45678"
  }
}

Response

200 OK
Content-Type: application/json

{
  "records": [
    {
      "type": "opportunity",
      "id": "Opportunity:09878",
      "data": {
        "document_name": "Oracle Sales Contract",
        "document_tags": {}
      }
    }
  ],
  "page": {
    "has_more": false
  }
}

Create data

Rather than creating records directly in the user's CRM, you'll invoke events to allow your users to create the appropriate records.

This is particularly important because CRM record creation frequently involves a large number of required or default fields that your app knows nothing about.

In some cases, your users may even use CRM Link to defer actual object creation to their CRM's native workflow engine.

To request creation of a record in the CRM you define and emit a create event.

Define create event

To define a create event, you'll pass an object to the events object of your CRM Object's definition in your CRM Link invocation with the following structure:

  • Key: this is the slug of the event, which you'll use when invoking the event in the Xkit API
  • Value: an object with the following structure
    • type: create
    • name: the user-facing name of the event, e.g. "Create Opportunity"
    • description: the user-facing description of the event and how the user should handle it, e.g. "Create new opportunities for sales documents that do not have one."
    • payloadSchema: Xkit-flavored JSON describing the schema of the payload you'll provide when invoking the event
await linkCRM(token, {
  objects: {
    opportunity: {
      events: {
        create_opportunity: {
          type: "create",
          name: "Create Opportunity",
          description: "Create new opportunities for sales documents that do not have one.",
          payloadSchema: {
            name: {
              type: "string",
              label: "Opportunity Name",
              description: "Desired name of the opportunity"
            }
          }
        }
      }
    }
  }
})

Invoke create event

Invoke the create event by using the Invoke Event endpoint.

If an object was created, it's id and mapped fields will be returned to you. Save the id of the returned CRM record to associate with an object in your database.

Here's an example request and response for invoking a create event for a CRM object with the slug opportunity and an event with the slug create_opportunity:

Request

POST /api/crm/1234/objects/opportunity/events/create_opportunity_for_document HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

{
  "payload": {
    "name": "Apple Sales Contract"
  }
}

Response

200 OK
Content-Type: application/json

{
  "record": {
    "type": "opportunity",
    "id": "Opportunity:09878",
    "data": {
      "document_name": "Oracle Sales Contract",
      "document_tags": {}
    }
  }
}

Update data

Rather than updating data directly in the user's CRM, you'll invoke events to allow your users to update the data in a way that makes sense for their CRM.

Here's how handling an update looks from the user's perspective:

Handling an update event in CRM Link

In some cases, your users may even use CRM Link to defer actual updates to their CRM's native workflow engine.

To request the update of an existing CRM record, you'll define and emit an update event in the context of a record previously fetched from the CRM.

Define update event

To define an update event, you'll pass an object to the events object of your CRM Object's definition in your CRM Link invocation with the following structure:

  • Key: this is the slug of the event, which you'll use when invoking the event in the Xkit API
  • Value: an object with the following structure
    • type: update
    • name: the user-facing name of the event, e.g. "Document Updated"
    • description: the user-facing description of the event and how the user should handle it, e.g. "Occurs when relevant document properties change."
    • payloadSchema: Xkit-flavored JSON describing the schema of the payload you'll provide when invoking the event
await linkCRM(token, {
  objects: {
    opportunity: {
      events: {
        document_updated: {
          type: "update",
          label: "Document Updated",
          description: "Occurs when relevant document properties change.",
          payloadSchema: {
            name: {
              label: "Document Name",
              description: "Updated name of the document",
              type: "string"
            },
            updated_at: {
              label: "Document Last Update Time",
              description: "ISO 8601 Date/Time of the last update made to the document",
              type: "string",
              format: "date"
            }
          }
        }
      }
    }
  }
})

Invoke update event

Invoke the update event by using the Invoke Event endpoint.

The updated object will be returned to you with its mapped fields.

Here's an example request and response for invoking a update event for a CRM object with the slug opportunity, the CRM Record Opportunity:09876 and an event with the slug document_updated:

Request

POST /api/crm/1234/objects/opportunity/Opportunity:09876/events/document_updated HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

{
  "payload": {
    "name": "Sales Contract",
    "updated_at": "2022-05-17T23:17:53Z"
  }
}

Response

200 OK
Content-Type: application/json

{
  "record": {
    "type": "opportunity",
    "id": "Opportunity:09876",
    "data": {
      "document_name": "Sales Contract",
      "document_tags": {}
    }
  }
}

Get changes to data

Xkit uses Webhooks to notify your application that data in the CRM relevant to your application has changed.

There are three types of webhooks:

  • Create: an object has been created in user's CRM
  • Update: a field in the CRM Object's mapping has changed
  • Delete: a CRM object has been deleted

To receive webhooks, you'll need to subscribe to them. There are 2 ways of subscribing to webhooks:

  • subscribing to webhooks for specific CRM Object
  • subscribing to webhooks for objects that match criteria for one of search events

Configure Webhook URL

In the developer portal, configure the URL Xkit should call to initiate a webhook and the API key we should include in the Authorization header.

Subscribe to Webhook for specific CRM record

Subscribe to a webhook by calling the Webhook Subscribe endpoint for the specific CRM record.

Example request:

POST /api/crm/1234/objects/opportunity/Opportunity:09876/subscriptions HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

This endpoint returns a 204 and contains no data.

Example response:

204 No Content

To remove the subscription send a DELETE request to the same URL

Example request:

DELETE /api/crm/1234/objects/opportunity/Opportunity:09876/subscriptions HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

The response would again be a 204

Example response:

204 No Content

Subscribe to Webhook for CRM records that match search event criteria

Subscribe to a webhook by calling the Webhook Subscribe endpoint for CRM records that match criteria of specific event

Example request:

POST /api/crm/1234/objects/opportunity/events/find_proposal_opportunities/subscriptions HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

{
  "payload": {
    "account_id": "555ABC"
  }
}

This endpoint returns a 204 and contains no data.

Example response:

204 No Content

To remove the subscription send a DELETE request to the same URL and with the same payload

** Example request **

DELETE /api/crm/1234/objects/opportunity/events/find_proposal_opportunities/subscriptions HTTP 1.1
Host: app.xkit.co
Authorization: Basic 123:456

{
  "payload": {
    "account_id": "555ABC"
  }
}

Response is again a 204

Example response:

204 No Content

Webhook Payload

Webhook payloads are JSON objects with the following structure:

  • event: the Webhook event object
    • type: A string which is create, update, or delete, corresponding to the type of event
    • record: the CRM record which has been affected
    • connection: identifies the connection the object belongs to
    • platform_context: identifies the platform context the object belongs to

Example Payload:

POST <webhook url> HTTP 1.1
Content-Type: application/json
Authorization: Bearer <api key>

{
  "event": {
    "type": "update",
    "record": {
      "type": "opportunity",
      "id": "Opportunity:09876",
      "data": {
        "document_name": "Apple Opportunity Sales Contract",
        "document_tags": {}
      }
    }
    "platform_context": {
      "id": "usr5c7e8c43"
    },
    "connection": {
      "id": "12345"
    }
  }
}

Up next

Your app in the CRM

Allow users to view and interact with your app from inside their CRM

Read more ▶

Ready to build your CRM app?

Integrate every CRM with one build, request access to get started.