Skip to main content

Close Reference

Close API key

To sync your Close data to your Sequin database, you will eventually want to provide us with a Close API key generated by an admin account. If you don't use an admin account's API key, there's a risk that on occasion some Close objects will be missing fields in your database. (This is because, for privacy reasons, Close hides some fields from their event log after one hour.)

However, if you're not an admin for your Close account and are just starting with Sequin, it's fine to use a regular API key. You can switch your API key to an admin one at any time in the future.

Close database schema

Your Sequin database will contain Close data for the following entities:

  • Activity
  • Contact
  • Email Template
  • Lead
  • Lead Status
  • Opportunity
  • Opportunity Status
  • Pipeline
  • Role
  • Task
  • User Account

More about each below:

Activity (activity)

An Activity belongs to a Lead and can represent any type of activity that was performed on a Lead or its Contacts (e.g. Calls, Emails, Notes, etc.).

Primary references

  • lead_id: Appears on every Activity.
  • contact_id: If the activity involved a Contact, it will have a contact_id as well.

Contact (contact)

A Contact represents an individual person within a company/organization that you're selling to. Each Contact belongs to exactly one Lead and can contain multiple phone numbers, email addresses and URLs.

contact has a custom_fields column which is a jsonb column mapping custom field IDs to the values for a contact. See "Note about custom fields" below.

Primary references

  • lead_id: Appears on every Contact.

Email template (email_template)

Email Templates are predefined emails that can be used over and over again when sending email. They save time when sending emails one at a time via the Close UI, and they are also used when initiating a single Bulk Email.

Lead (lead)

Leads are the most important object in Close. They represent a company or organization and can contain contacts, tasks, opportunities, and activities. In fact, these other objects must be children of a Lead. You can think of a Lead in Close like both a "lead" and "account" in the terminology of some other CRMs.

lead has a custom_fields column which is a jsonb column mapping custom field IDs to the values for a lead. See "Note about custom fields" below.

Primary references

  • status_id: Current status of the Lead. Maps to lead_status.

Lead Status (lead_status)

Lead Statuses are a customizable list of stages a Lead can be in.

To get a Lead along with its status label, use this query:

select lead.*, lead_status.label as status_label
from lead
inner join lead_status on = lead.status_id;

Opportunity (opportunity)

Opportunities represent a potential deal with a given company/Lead.

Opportunities have columns that store monetary values, like value and expected_value. These columns are integers and represent the value in cents.

Primary references

  • lead_id: The Lead the Opportunity belongs to.
  • status_id: Current status of the Opportunity. Maps to opportunity_status.
  • contact_id: Primary Contact associated with the Opportunity.

Opportunity Status (opportunity_status)

Opportunity Statuses are a customizable list of stages an Opportunity can be in.

To get an Opportunity along with its status label, use this query:

select opportunity.*, opportunity_status.label as status_label
from opportunity
inner join opportunity_status on = opportunity.status_id;

Pipeline (pipeline)

Pipelines are a group of Opportunity Statuses. They allow you to group your Opportunity Statuses into separate categories that make sense for the different teams and workflows at your company. For example, you can have a "Sales" Pipeline and a separate "Professional Services" Pipeline.

Role (role)

Roles define what users in your organization can or can not do. Every role has a set of permissions that represent actions users can do in Close.

Task (task)

Tasks are action items with a given date that are assigned to a sales rep.

Incomplete tasks (is_complete is false) show in the sales rep's inbox, whereas complete tasks (is_complete is true) are shown in the archive. Archived tasks of certain types are automatically deleted after a certain amount of time.

For a list of the different types of possible Tasks, see the Close documentation.

Primary references

  • lead_id: The Lead the Task belongs to.
  • assigned_to: The User Account to which the Task is assigned.
  • object_id: Some Task types have a corresponding object, which is represented by the object_id and object_type fields. Because this relationship is polymorphic, this column is not a foreign key.

User Account (user_account)

A User Account represents Close user accounts, usually your co-workers / sales reps inside your company/organization.

Note about custom fields

Close supports "custom fields" for some entities, like Contact and Lead. For example, say an organization has a custom field for Contact, "Preferred meeting time." With Sequin, that would appear in Postgres as a map of that custom field's ID to its value:

"custom.ccf_0HHTVilnCtPmGp46neRr0n8xNYSIOr9XAhhJ6z7v2Vw": "Mon & Wed Afternoons PST"

We know this interface is not ideal. We're going to improve this interface by instead storing this map in a separate table soon (e.g. contact_custom_fields).

The syncing process

Sequin workers first backfill your database with all your Close data by paginating through all Close API endpoints.

Then, after the backfill, Sequin workers poll Close's /events endpoint twice per second to ingest any creates, updates, or deletes.

Our general sync strategy for Close is very similar to our strategy for Stripe. You can read more about how Sequin's syncing process for Stripe works on our blog.


Your Sequin database is read-only.

We advocate for a one-way data flow: read from your Sequin database, write to Close's API. Any changes will flow down to your Sequin database for you to read again.

Sometimes, you want to make sure that changes that you just wrote have been synced to your database. We call this scenario a read-after-write.

To do so, you can call our wait endpoint. To find the URL for your sync's wait endpoint, just click "Connect" in the Sequin console. Wait endpoints take this form:

Where kind is the platform, like stripe or close. id is the Sequin ID of your sync.

A wait endpoint only returns after we've confirmed your database is up-to-date. So, you can weave it into your workflow like this:

  1. Make a write request directly to the API
  2. Call your sync's wait endpoint
  3. When #2 completes, read from your Sequin database

Here's an example curl request to a wait endpoint on Sequin:

> curl
< { "ok": true }

Note: The wait endpoint is in alpha and experimental. We may add additional properties to the response in the near future.


Your Sequin database will contain all your Close data - which includes PII and sensitive information. We take the security of that data seriously.

Please read about our full security practices. Here is a short synopsis of how we keep your Close data secure:

  • You supply us with an API key which is encrypted at rest. The Sequin application database is only accessible through a bastion host.
  • We only access customer databases by request or to diagnose a sync issue.
  • Sequin workers first backfill your database with all your Close data. Then, after the backfill, Sequin workers poll Close's events endpoint every second to keep your data in-sync.
  • Data flows directly from Close, through Sequin workers, to your database. We don't cache or store Close data anywhere else.
  • We use Sentry and Datadog for error monitoring. Sometimes errors Datadog catches will contain API response data. But these are minimized and our logs in Datadog have a shelf-life of 30 days.
  • By default, Sequin provisions a private database and a database user for you on a shared RDS instance. While Sequin shared instances are secure, we can also sync to a database you own for greater peace of mind.