# Actors Source: https://docs.attio.com/docs/actors Keeping track of who did what In various places in the Attio API, you will see the concept of an "actor". An actor is something that performs actions inside Attio. A workspace member is the prime example of an actor, but you will also encounter apps and automations as actors. ## Types of Actors An Actor is made up of two things: a type and an ID. The current list of actors types and their corresponding ID format is as follows: * `workspace-member` - A human user who is signed into a workspace. Comes with a unique UUID. You can get further information about the workspace member, e.g. name, avatar and email address, using the [list workspace members endpoints](/rest-api/endpoint-reference/workspace-members/get-a-workspace-member). * `api-token` - An integration using the developer API. Comes with a unique UUID for the token. * `system` - An internal part of the Attio system. For example, communications intelligence updates are registered with system actors. Always comes with a `null` ID. Actors are recorded in various parts of the system. Every attribute value write, for example, includes the actor who wrote it, e.g: ```json The actor who wrote a particular value theme={"system"} "created_by_actor": { "type": "workspace-member", "id": "175bec0c-f06a-4c45-9962-7a7a6be28b8a" } ``` Actors are often encountered via the "actor reference" attribute type. Every standard object includes a `created_by` attribute of this type. For more information, please see the [actor reference](/docs/attribute-types/attribute-types-actor-reference.mdx) documentation. # Archiving vs deleting Source: https://docs.attio.com/docs/archiving-vs-deleting Attio uses two separate but related concepts: **archiving** and **deleting**. **Deleting** should be considered permanent. Any data you delete will eventually be removed from our servers entirely, without the ability for restoration. As such, deletes should be handled extremely carefully. When using our API, deleting occurs using the conventional REST semantics of the `DELETE` HTTP verb. **Archiving** is softer, allowing data to remain in the system, albeit in a more hidden state. The exact behaviour of archived data will depend on the object you are archiving, but the behaviour will be documented for the given endpoint. When using our API, archiving occurs by setting the `is_archived` property to `true`, and restored by setting it to `false`. # Overview Source: https://docs.attio.com/docs/attribute-types/attribute-types Attributes are used to model data on objects and lists. Standard objects come with a series of "system" attributes predefined, but users and developers can create and modify their own attributes as well. ## Attribute properties In the API, attributes are presented as a set of properties. Some attribute types have specific properties (e.g. an actor reference attribute has the `referenced_actor_type` property), but all attributes have the following properties: * `id`, which is a [composite ID](/docs/slugs-and-ids) composed of `(workspace_id, object_id, attribute_id)` * `title`, the human-readable name of the attribute (e.g. `"Name"`) * `description`, an optional human-readable description (e.g. `"The name as registered in our database"`) * `api_slug`, a shorthand way for developers to refer to this attribute (e.g. `"name"`) * `type`, one of the enumerated types below (e.g. `"text"`) * `is_archived`, whether the [attribute has been archived](/docs/archiving-vs-deleting) * `is_required`, whether a value is required when creating the record or list entry * `is_unique`, whether the value for this attribute is unique among all other records or list entries of that type * `is_multiselect`, whether you can write more than one value to this attribute * `is_default_value_enabled` and `default_value`, see the [default values guide](/docs/default-values) * `created_at`, a timestamp of when this attribute was first created * `config`, an object containing specific configuration for `currency` or `record_reference` types For more information about attributes, you can find our [attribute APIs here](/rest-api/endpoint-reference/attributes). ## Attribute values Attribute values represent the value of the given attribute on a given record or list entry. They also have a set of common properties, that you'll see referenced throughout this guide: * `active_from`, a timestamp showing when this value was created * `active_until`, either a timestamp (meaning the value was readable until that point in time) or `null`, meaning the value is still currently active. Most endpoints will only return active values, meaning this value is usually `null`. In special cases, such as the [list record attribute values API](https://attio.readme.io/reference/get_v2-objects-object-records-record-id-attributes-attribute-values), you can also query historic data. * `created_by_actor`, a reference to the `id` and `type` of the [Actor](/docs/actors) who created this value * `attribute_type`, matches the `type` property on the Attribute itself (e.g. `"text"`) ## Attribute types Attio currently has 17 different attribute types, and they can behave differently when creating, viewing, filtering and sorting. This guide will walk through each type, with examples of where you might find them and how to work with them: * [Actor reference](/docs/attribute-types/attribute-types-actor-reference) * [Checkbox](/docs/attribute-types/attribute-types-checkbox) * [Currency](/docs/attribute-types/attribute-types-currency) * [Date](/docs/attribute-types/attribute-types-date) * [Domain](/docs/attribute-types/attribute-types-domain) * [Email address](/docs/attribute-types/attribute-types-email-address) * [Interaction](/docs/attribute-types/attribute-types-interaction) * [Location](/docs/attribute-types/attribute-types-location) * [(Personal) name](/docs/attribute-types/attribute-types-personal-name) * [Number](/docs/attribute-types/attribute-types-number) * [Phone number](/docs/attribute-types/attribute-types-phone-number) * [Rating](/docs/attribute-types/attribute-types-rating) * [Record reference](/docs/attribute-types/attribute-types-record-reference) * [Select](/docs/attribute-types/attribute-types-select) * [Status](/docs/attribute-types/attribute-types-status) * [Text](/docs/attribute-types/attribute-types-text) * [Timestamp](/docs/attribute-types/attribute-types-timestamp) # Actor reference Source: https://docs.attio.com/docs/attribute-types/attribute-types-actor-reference References to workspace members and others Actor references are used to link to [actors](/docs/actors) in Attio. You're most likely to encounter this attribute via the `created_by` attribute which is available on every object, the `owner` attribute on a deal object, or the `strongest_connection_user` on a company or person. Actor reference attributes can be single-select or multi-select. Please note, in the mobile and web clients, attributes of this type are marked as "User" attributes. ### Reading values Actor reference values have two properties, `referenced_actor_type` and `referenced_actor_id`. The `referenced_actor_type` can be one of `"api-token"`, `"workspace-member"` or `"system"`. The `referenced_actor_id` is a UUID, or the value `null`, that uniquely identifies the actor. ```json Example: workspace member theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "actor-reference", "referenced_actor_type": "workspace-member", "referenced_actor_id": "fbe75eb0-d704-4d12-9e41-aa187e60ed73" } ``` ### Writing values Currently, the only type of [actor](/docs/actors) that can be explicitly set in our API is `"workspace-member"`. We may expand this list in future. When writing references to workspace members, we allow you to identify actors by email addresses. You may do this either by passing an email address string directly, or by using an object with the key `workspace_member_email_address`. Actor reference attributes may be multi-select or single-select. When writing to multi-select attributes, you must always wrap values in an array. Single-select attributes accept unwrapped data. ```json Using email string theme={"system"} { "owner": ["[email protected]"] } ``` ```json Single-select string theme={"system"} { "owner": "[email protected]" } ``` ```json Using workspace_member_email_address theme={"system"} { "owner": [ { "workspace_member_email_address": "[email protected]" } ] } ``` You may also specify the actor type and ID explicitly using an object with the keys `referenced_actor_type` and `referenced_actor_id`. ```json Using workspace member ID theme={"system"} { "owner": [ { "referenced_actor_type": "workspace-member", "referenced_actor_id": "50cf242c-7fa3-4cad-87d0-75b1af71c57b" } ] } ``` ### Filtering Actor reference values can only be filtered using both the `referenced_actor_type` and `referenced_actor_id` properties. If using explicit operators, only the `$eq` operator is supported. For example: ```json Value written by workspace member theme={"system"} { "filter": { "created_by": { "referenced_actor_type": "workspace-member", "referenced_actor_id": "ec44a06c-b690-4e4f-95b6-757fb4e2f55f" } } } ``` ```json Value written by API token theme={"system"} { "filter": { "created_by": { "referenced_actor_type": "api-token" } } } ``` ```json Expanded format theme={"system"} { "filter": { "created_by": { "referenced_actor_type": { "$eq": "api-token" } } } } ``` # Checkbox Source: https://docs.attio.com/docs/attribute-types/attribute-types-checkbox Modelling boolean values Checkbox attributes are used to represent boolean values (`true` and `false`). In the UI, they are presented to users as a checkbox, hence the name. There are no predefined checkbox attributes on any of the standard objects. As a result, checkbox attributes will only be present when added by the user. Checkbox attributes may only be single-select. ### Reading values If the checkbox is checked, you'll get the `true` property back, otherwise it will be `false`. This attribute does not support null values. ```json Example: a checked attribute theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "checkbox", "value": true } ``` ### Writing values To write checkbox attribute values, you can use either the boolean values `true`/`false` or their string equivalents `"true"`/`"false"`. We support setting these values directly as raw booleans/strings, or by using an object with a single key, `value`. We only support single-select checkbox attributes, so you may always write checkbox values without wrapping the values in an array (array values containing a single element are also supported). ```json Using boolean theme={"system"} { "a_custom_checkbox_attribute": true } ``` ```json Using string theme={"system"} { "a_custom_checkbox_attribute": "true" } ``` ```json Using array theme={"system"} { "a_custom_checkbox_attribute": [true] } ``` ```json Using object theme={"system"} { "a_custom_checkbox_attribute": [ { "value": true } ] } ``` ### Filtering Checkbox attribute values can be filtered by true/false. If using explicit operators, only the `$eq` operator is supported. For example: ```json Records where checkbox is checked theme={"system"} { "filter": { "a_custom_checkbox_attribute": true } } ``` ```json Expanded format theme={"system"} { "filter": { "a_custom_checkbox_attribute": { "value": { "$eq": false } } } } ``` # Currency Source: https://docs.attio.com/docs/attribute-types/attribute-types-currency More than just numbers Currency attributes represent quantities of money. They are similar to number attributes, allowing storing numbers with up to four decimal places of precision, but are presented differently in the UI with a currency symbol usually alongside. Two examples of currency attributes are the `funding_raised_usd` attribute on the company object, and the `value` attribute on the deal object. There is a `currency_code` property returned from the API on each attribute value, but please note that this is shared among all attribute values of the attribute; it is not possible to override currency for a particular record or entry. Currency attributes can only be single-select. ### Configuration When creating currency attributes, you can specify two configuration properties: * `default_currency_code` - The [ISO4217](https://www.iso.org/iso-4217-currency-codes.html) currency code e.g. `USD` or `EUR`. All values for the attribute inherit this value. * `display_type` How the currency should be displayed across the app. See [MDN for more details](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#currencydisplay). ```http Specifying configuration when creating a currency attribute theme={"system"} POST /v2/objects/:object/attributes HTTP/1.1 Authorization: Bearer <> Content-Type: application/json { "title": "Amount owed", "api_slug": "amount_owed", "type": "currency", "config": { "currency": { "default_currency_code": "USD", "display_type": "symbol" } } } ``` ### Reading values Currency attributes have two properties, `currency_code` (string) and `currency_value` (number). This attribute does not support null values. ```json Example: $499.00 theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "currency", "currency_value": "499.00", "currency_code": "USD" } ``` ### Writing values Currency values can be written using floating point numbers. We accept values with up to 4 decimal places of precision. You do not need to pass floating point numbers explicitly; we will automatically convert integers to their floating point equivalents. Where possible, Attio will convert strings into numbers. For example, the string `"4.99"` will be parsed as the float `4.99`. As currency attributes may only be single-select, you may always write values without wrapping in an array if preferred. We also support writing currency values using an object with a single key, `currency_value`. ```json Using float theme={"system"} { "amount_owed": 4.99 } ``` ```json Using string theme={"system"} { "amount_owed": "4.99" } ``` ```json Using object theme={"system"} { "amount_owed": [ { "currency_value": "399.00" } ] } ``` It is not possible to specify the `currency_code` since this is inherited from the attribute. ### Filtering Currency attribute values can be filtered by their value, using either JSON strings or numbers. You can filter for an exact value using the implicit syntax, or use the `$eq`,`$gt`,`$gte`,`$lt`,`$lte` operators with the explicit syntax. ```json Finding records with an exact currency value theme={"system"} { "filter": { "amount_owed": "399.00" } } ``` ```json Currency at least 500 theme={"system"} { "filter": { "amount_owed": { "currency_value": { "$gte": 500 } } } } ``` # Date Source: https://docs.attio.com/docs/attribute-types/attribute-types-date A timezone-less calendar date Date attributes are used to represent a single calendar year, month and day, independent of timezone. Attio exclusively works with the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format, i.e. `YYYY-MM-DD` e.g. `2023-11-24`. There is only one default example of a date attribute, `foundation_date` on the company object. Date attributes can only be single-select. ### Reading values Date attributes have a single property, `value` (a string). ```json Example: 24th November, 2023 theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "date", "value": "2023-11-24" } ``` ### Writing values Date values can be written by passing an ISO 8601 date string. If hours, months, seconds or timezones are provided, they will be trimmed. For example: * `'2023'` → `'2023-01-01'` * `'2023-01'` → `'2023-01-01'` * `'2023-01-02'` → `'2023-01-02'` * `'2023-01-02T13:00'` → `'2023-01-02'` * `'2023-01-02T14:00:00'` → `'2023-01-02'` * `'2023-01-02T15:00:00.000000000'` → `'2023-01-02'` * `'2023-01-02T15:00:00.000000000+02:00'` → `'2023-01-02'` If a timezone is provided that would result in a different calendar date in UTC, the date will be coerced to UTC and then the timezone component will be trimmed. For example, the value `'2023-01-02T23:00:00-10:00'` will be returned as `'2023-01-03'`. As date values are always single-select, you may write values either by passing the date string directly, or by wrapping a single value in an array. You may also write date values using an object with a single `value` key. ```json Using string theme={"system"} { "foundation_date": "2004-07-29" } ``` ```json Using object theme={"system"} { "foundation_date": [ { "value": "2004-07-29" } ] } ``` ### Filtering Date attribute values can be filtered by their value. You can filter for an exact date using the implicit syntax, or use the `$eq`,`$gt`,`$gte`,`$lt`,`$lte` operators with the explicit syntax. ```json Companies founded on 2023-11-24 theme={"system"} { "filter": { "foundation_date": "2023-11-24" } } ``` ```json Companies formed after the year 2000 theme={"system"} { "filter": { "foundation_date": { "value": { "$gte": "2000-01-01" } } } } ``` # Domain Source: https://docs.attio.com/docs/attribute-types/attribute-types-domain An internet domain Domain attributes represent an internet domain, for example, "apple.com". Attio represents domains as structured objects rather than raw strings, allowing filtering and display of specific domain properties such as the root domain. Please note that domain attributes store domains, not URLs. Any inputted values will have paths and query parameters trimmed. If you would like to store full URLs, please use a text attribute. It isn't currently possible to create your own domain attributes, so you'll find only the multi-select `domains` attribute on a company object. ### Reading values There are two properties on a domain attribute, `domain` and `root_domain`. The `domain` property contains the entire domain, after normalization. The `root_domain` property is the top-most part of the domain besides the public suffix. For example, the root domain of `"app.attio.com"` would be `"attio.com"`. ```json Example: app.attio.com theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "domain", "domain": "app.attio.com", "root_domain": "attio.com" } ``` ### Writing values To write domain values, simply pass the string of the domain. The `root_domain` property will automatically be inferred from input values so there is no need to write it yourself. You may also write domain values using an object with a single key, `domain`. As the `domains` attribute is multi-select, you must always pass values wrapped in an array. ```json Using string (single value) theme={"system"} { "domains": ["app.attio.com"] } ``` ```json Using string (multiple values) theme={"system"} { "domains": ["app.attio.com", "attio.com"] } ``` ```json Using object theme={"system"} { "domains": [ { "domain": "app.attio.com" } ] } ``` ### Filtering Domain attribute values can be filtered by either the `root_domain` or `domain` property, and support several operators: * `$eq` for an exact match * `$not_empty` for any value present * `$contains` , `$starts_with` and `$ends_with` In implicit mode, the `domain` property is checked for equality, otherwise you can use the explicit syntax to combine the properties and operators above. ```json Companies where domain=app.attio.com theme={"system"} { "filter": { "domain": "app.attio.com" } } ``` ```json ...where subdomain=attio.com theme={"system"} { "filter": { "domains": { "root_domain": { "$eq": "attio.com" } } } } ``` ```json ...where domain includes attio theme={"system"} { "filter": { "domains": { "domain": { "$contains": "attio" } } } ``` # Email address Source: https://docs.attio.com/docs/attribute-types/attribute-types-email-address An email address Email address attributes are a string referencing an internet email address. For example, an email address might be `"[email protected]"`. Like [domain](/docs/attribute-types/attribute-types-domain) attributes, we do some parsing of the email domain part, as well as validating the general shape of an email address overall. It isn't currently possible to create your own email address attributes. You'll find only the multiselect `email_addresses` attribute on a person object, or the single attribute `email_address` attribute on the user standard object. ### Reading values There are five properties available on this attribute: * `email_address` - the normalized form of the email address, this is the one you are most likely to use * `original_email_address` - the email as it was originally input to the system, without normalization * `email_domain` - the full domain part of the email address * `email_root_domain` - the root domain part of the email address * `email_local_specifier` - the local part of the email address ```json Example: person@company.com theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "email-address", "email_address": "[email protected]", "original_email_address": "[email protected]", "email_domain": "company.com", "email_root_domain": "company.com", "email_local_specifier": "person" } ``` ### Writing values Email address values can be written by passing in a string of the email you would like to write. We also support passing values with a single key, `email_address`. We strictly validate that email addresses have valid domain and local part formats. Attio will automatically infer the root domain, local specify and other properties available on read so there is no need to write them yourself. If writing to a multi-select attribute, you must wrap your input values in an array. ```json Writing to email_addresses theme={"system"} { "email_addresses": ["[email protected]", "[email protected]"] } ``` ```json Writing to email_address theme={"system"} { "email_address": "[email protected]" } ``` ```json Using object theme={"system"} { "email_addresses": [ { "email_address": "[email protected]" } ] } ``` ### Filtering Email attribute values can be filtered by the `email_address`, `email_domain`, `email_root_domain` and `email_local_specifier` properties, and support several operators: * `$eq` for an exact match * `$contains` , `$starts_with` and `$ends_with` In implicit mode, the `email_address` property is checked for equality, otherwise you can use the explicit syntax to combine the properties and operators above. ```json People where email_addresses=person@company.com theme={"system"} { "filter": { "email_addresses": "[email protected]" } } ``` ```json ...where domain=attio.com theme={"system"} { "filter": { "email_addresses": { "email_domain": { "$eq": "attio.com" } } } } ``` ```json ...where local part includes person theme={"system"} { "filter": { "email_addresses": { "email_local_specifier": { "$contains": "person" } } } ``` # Interaction Source: https://docs.attio.com/docs/attribute-types/attribute-types-interaction Calendar events and emails Interactions are quite a generic concept, used to model when a given actor interacted with a record in a particular way. Presently, Attio has just two types of interaction: * Email interactions (`first_email_interaction` and `last_email_interaction`) * Calendar interactions (`first_calendar_interaction`, `last_calendar_interaction` and `next_calendar_interaction`) These attributes are available on both the Company and Person objects, although they are enriched and not available on every billing plan. For more information about these attributes, [please see our Enriched data help page](https://attio.com/help/reference/data-and-syncing/enriched-data#communication-intelligence). ### Reading values Interaction attribute values have an `interaction_type` property, which can be either `"email"` or `"calendar-event"`, and an `interacted_at` timestamp property in ISO8601 format. There is also an `owner_actor` property, which is an object relating the [actor](/docs/actors) who created this interaction (this is different from the `created_by` attribute value property which could be e.g. a system actor). ```json Example: last email received by Tom on 2023-11-25 theme={"system"} { "active_from": "2023-11-25T15:21:06.447000000Z", "active_until": null, "created_by_actor": { "type": "system", "id": null }, "attribute_type": "interaction", "interaction_type": "email", "interacted_at": "2023-11-25T15:21:06.447000000Z", "owner_actor": { "type": "workspace-member", "id": "50cf242c-7fa3-4cad-87d0-75b1af71c57b" // Tom } } ``` ### Writing values It is not currently possible to write Interaction values, they are only created by the Attio system. ### Filtering There are three properties of interactions that can be used in filtering: * `owner_member_id` filters by the workspace member ID that is the `owner_actor`, this supports `$eq` and `$not_empty` operators * `interacted_at` (timestamp) supports `$eq`, `$gte`, `$gt`, `$lte` and `$lt` operators * `interaction_type` can also be filtered by `$eq` and `$not_empty` ```json Companies ... which have had an email interaction theme={"system"} { "filter": { "last_email_interaction": { "owner_member_id": { "$not_empty": true } } } } ``` ```json ... with whom Tom had a recent meeting theme={"system"} { "filter": { "last_calendar_interaction": { "owner_member_id": "50cf242c-7fa3-4cad-87d0-75b1af71c57b", "interacted_at": { "$gte": "2023-11-01" } } } } ``` ```json ... via email theme={"system"} { "filter": { "first_email_interaction": { "interaction_type": "email" } } } ``` # Location Source: https://docs.attio.com/docs/attribute-types/attribute-types-location A physical location in the world Location attributes model a physical location in the world. We store all location properties (address lines, postcode, country code, etc) on a single attribute value, rather than separate attributes. This means that when working with locations, updates must be atomic—every property must be specified, even if it is null. You'll find an example of this attribute as `primary_location` on both person and company objects. Locations have the following properties: * `line_1` - the first line of the address, e.g. `"1 Infinite Loop"` * `line_2` - the second line of the address e.g. `"Block 1"` * `line_3`, `line_4`, same as above * `locality` - the town, neighbourhood or area, e.g. `"Cupertino"` * `region` - the state, county, province or region, e.g. `"CA"` * `postcode` - the postal or zip code, e.g. `"95014"` * `country_code` - the ISO 3166-1 alpha-2 country code, e.g. `US` * `latitude` - latitudinal coordinates, e.g. `"37.331741"` * `longitude` - longitudinal coordinates, e.g. `"-122.030333"` There are some properties which are not presently shown in the Attio app but are captured by the API—for example, address lines or postcodes. ### Reading values Depending on your use case, there are various properties of a location that might be relevant for you. The API will return the full object as structured data, without attempting to format it: ```json Example: Apple Headquarters theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "location", "line_1": "1 Infinite Loop", "line_2": null, "line_3": null, "line_4": null, "locality": "Cupertino", "region": "CA", "postcode": "95014", "country_code": "US", "latitude": "37.331741", "longitude": "-122.030333", } ``` ### Writing values When writing location values, Attio will intelligently parse strings into structured location data. ```json json theme={"system"} { "primary_location": "1 Infinite Loop, Cupertino, CA, 95014, US" } ``` You may also specify each location property explicitly using an object value. When using the object syntax, we require that updates to a location attribute must specify a value for every attribute, even if it is `null`. ```json Using object theme={"system"} { "primary_location": { "line_1": "1 Infinite Loop", "line_2": null, "line_3": null, "line_4": null, "locality": "Cupertino", "region": "CA", "postcode": "95014", "country_code": "US", "latitude": "37.331741", "longitude": "-122.030333" } } ``` ### Filtering The properties `line_1`, `line_2`, `line_3`, `line_4`, `locality`, `region` and `postcode` can all be filtered by `$eq`, `$contains`, `$starts_with` and `$ends_with` operators. The property `country_code` can be filtered by `$eq` and `$starts_with` operators. ```json People in Cupertino, California theme={"system"} { "filter": { "primary_location": { "locality": "Cupertino", "region": "CA", "country_code": "US" } } } ``` ```json ...where locality contains "cuper" theme={"system"} { "filter": { "primary_location": { "locality": { "$contains": "cuper" /* Case insensitive */ } } } } ``` It is not currently possible to filter by latitude/longitude. # Number Source: https://docs.attio.com/docs/attribute-types/attribute-types-number Quantities, sums and metrics Number attributes store floating point numbers with up to four decimal places of precision. An example of a number attribute is the `twitter_follower_count` attribute on both the company and person objects. Only single-select number attributes are supported. ### Reading values Number attribute values have a `value` property: ```json Example: 14 Twitter followers theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "number", "value": 14 } ``` ### Writing values To write number values, simply pass your desired number, either as an integer or a float. Alternatively, you can use an object with a single `value` property. ```json Using number theme={"system"} { "a_custom_number_attribute": 3.1415 } ``` ```json Using object theme={"system"} { "a_custom_number_attribute": [ { "value": 3.1415 } ] } ``` Please note that `twitter_follower_count` is a system attribute and cannot be written to from the API. ### Filtering Numbers can be filtered by the operators `$eq`, `$gte`, `$gt`,`$lte`,`$lt`. The implicit syntax does an exact equality check: ```json Finding records with 14 Twitter followers theme={"system"} { "filter": { "twitter_follower_count": 14 } } ``` ```json ... with more than 1000 followers theme={"system"} { "filter": { "twitter_follower_count": { "value": { "$gte": 1000 } } } } ``` # (Personal) name Source: https://docs.attio.com/docs/attribute-types/attribute-types-personal-name A person's name Name attributes represent a person's name. They have three properties: `first_name`, `last_name` and `full_name`. Only the person object has a `name` attribute. Name attributes cannot be created by users. ### Reading values All three properties are present in responses: ```json Example: John Smith theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "personal-name", "first_name": "John", "last_name": "Smith", "full_name": "John Smith" } ``` ### Writing values Attio provides two syntaxes for writing name values, a string syntax and an object syntax. If possible, we recommend using the object syntax as it provides full control over the name values you create. When writing values using the object syntax, all three properties must be set. ```json Using object theme={"system"} { "name": { "first_name": "John", "last_name": "Smith", "full_name": "John Smith" } } ``` When writing using a string, the string must match format 'Last name(s), First name(s)'. Text without a comma is interpreted as solely comprising the first name. Further commas will be ignored and assumed to be part of the first name. ```json Using string theme={"system"} { "name": "Smith, John" } ``` ### Filtering You can filter by any of the properties, using these operators: * `$eq` * `$not_empty` * `$contains`, `$starts_with`, `$ends_with` Using the implicit filter syntax, you can search for exact matches of `full_name`, otherwise any combination of property/operator. ```json People exactly named John Smith theme={"system"} { "filter": { "name": "John Smith" } } ``` ```json ...where first_name starts with "jo" theme={"system"} { "filter": { "name": { "first_name": { "$starts_with": "jo" /* Case insensitive */ } } } } ``` ```json ... where last_name is specified theme={"system"} { "filter": { "name": { "last_name": { "$not_empty": true } } } } ``` # Phone number Source: https://docs.attio.com/docs/attribute-types/attribute-types-phone-number International telephone numbers Phone number attributes represent telephone numbers. They are represented in [E164 format](https://en.wikipedia.org/wiki/E.164) and always prefixed with a country code. The person object comes with a phone number attribute (`phone_numbers`), which is is a multi-select attribute, but users can also create their own phone number attributes on other objects or lists as well. There are three properties on a phone number: `original_phone_number` (as inputted by the user), `country_code` (an ISO 3166-1 alpha-2 country code) and `normalized_phone_number` (as set by Attio). All properties are represented as strings. ### Reading values ```json Example: a US telephone number theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "phone-number", "original_phone_number": "+15558675309", "normalized_phone_number": "+15558675309", "country_code": "US" } ``` ### Writing values You may either write phone number values as strings or objects. For both formats, you must provide sufficient information to identify the country code of the number. For string values, the phone number must be prefixed with the area code, starting with "+". Object values must include both a `original_phone_number` and `country_code` property. You may pass `null` to `country_code` if an area code prefix is provided as part of `original_phone_number`. All values are validated against the E164 format. Since the `phone_numbers` attribute is multi-select, you must always pass values as part of an array. ```json Using string theme={"system"} { "phone_numbers": ["+447777777777"] } ``` ```json Setting phone number with country theme={"system"} { "phone_numbers": [ { "original_phone_number": "+447777777777", "country_code": "GB" } ] } ``` ```json Setting just the number theme={"system"} { "phone_numbers": [ { "original_phone_number": "+44 7777777777", "country_code": null } ] } ``` ### Filtering Phone numbers can be filtered by equality or substrings (`$eq`,`$contains`,`$starts_with`,`$ends_with`). Note that the explicit property is called `phone_number`, internally Attio will use the normalized phone number for searching. The `country_code` property can also be filtered by `$eq` and `$not_empty`. ```json People by exact phone number theme={"system"} { "filter": { "phone_numbers": "+15558675309" } } ``` ```json ... with US phone numbers theme={"system"} { "filter": { "phone_numbers": { "country_code": { "$eq": "US" } } } } ``` ```json ... with part of a phone number theme={"system"} { "filter": { "phone_numbers": { "phone_number": { "$contains": "67530" } } } } ``` # Rating Source: https://docs.attio.com/docs/attribute-types/attribute-types-rating Star ratings from 0 to 5 Rating attributes are a numeric value from 0 to 5. In the UI, they are presented as a proportion of 5 stars. There are no default rating attributes in Attio, but they can be created by users and in the API. Only single-select rating attributes are permitted. ### Reading values Rating attribute values have a `value` property: ```json Example: 3 out of 5 stars theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "rating", "value": 3 } ``` ### Writing values To write rating values, you can either pass an integer directly, or an object with a single key, `value`. As all rating attributes are single-select, you may pass the value directly or as an array containing a single element. ```json Using number theme={"system"} { "performance": 4 } ``` ```json Using object theme={"system"} { "performance": [ { "value": 4 } ] } ``` ### Filtering Ratings can be filtered by the operators `$eq`, `$gte`, `$gt`,`$lte`,`$lt`. The implicit syntax does an exact equality check: ```json Finding records rated 4 stars theme={"system"} { "filter": { "performance": 4 } } ``` ```json ... with more than 3 stars theme={"system"} { "filter": { "performance": { "value": { "$gte": 3 } } } } ``` # Record reference Source: https://docs.attio.com/docs/attribute-types/attribute-types-record-reference Relationships and one-way links between records Record reference attributes are one of the most useful types of attribute. They allow pointing to other records of the same object, or records of other objects. When combined with features such as drill-down filters, it becomes possible to deeply relate the various parts of your data model. By default, all of the standard objects have at least one record reference: * Company has `team` (people), `associated_deals` (deals) and `associated_workspaces` (workspaces) * Person has `company` (company), `associated_deals`(deals) and `associated_users` (users) * Deal has `associated_people` (people) and `associated_company` (company) * User has `person` (person) and `workspace` (workspace) * Workspace has `users` (users) and `company` (company) ### A note about relationship attributes All of the example attributes above are also relationship attributes. [Relationship attributes](https://attio.com/help/reference/workspace/attributes#relationship-attributes) describe a relationship between two objects, which appear as a pair of record reference attributes, one on each object. Updating an attribute value on either of the attributes automatically updates the other attribute, which means you don't need to explicitly update both. For example, adding a person to a company by updating the company `team` property, will also update the `company` property on that person. Currently, you will be able to see relationship attributes alongside other non-relationship record reference attributes in the API. The attribute type is still marked as `record-reference`, but there is an additional property, `relationship`, that you can use to distinguish these. If the attribute is also a relationship attribute, the `relationship` property will be an object containing an `id` property. In the example below, our company's `team` attribute has a relationship with the person's `company` attribute: ```json Example "team" attribute on a company theme={"system"} { "id": { ... }, "title": "Team", "api_slug": "team", "type": "record-reference", "relationship": { "id": { "workspace_id": "14beef7a-99f7-4534-a87e-70b564330a4c", "object_id": "4e71c40b-7d35-463c-afcb-e339cfd6dbd1", // Person object "attribute_id": "41252299-f8c7-4b5e-99c9-4ff8321d2f96" // "Company" attribute on Person object } }, ... } ``` If the record reference attribute is not a relationship attribute, the `relationship` property will be set to `null`. In the web application, when setting up a relationship, the user specifies whether the relationship is many-to-many, many-to-one, one-to-many or one-to-one. It is possible to discern this relationship by looking at the `is_multiselect` property on each attribute: if `true`, this attribute is a "many", if `false` it is a "one". Unfortunately, at present it is not possible to create relationship attributes using the API; they can only be created in the web application and then used in the API. ### Configuration Record references are usually constrained to referencing a specific object. For example, you can't specify a deal for the company `team` attribute. This is accomplished with the configuration property `allowed_object_ids` which is an array of object IDs (slugs are supported when writing this property): ```http Create "owner" attribute which only supports People theme={"system"} POST /v2/objects/:object/attributes HTTP/1.1 Authorization: Bearer <> Content-Type: application/json { "title": "Owner", "api_slug": "owner", "type": "record-reference", "config": { "record_reference": { "allowed_objects": ["person"] } } } ``` In responses from the API, this appears as `allowed_object_ids`, like so: ```json Attribute definition response for "team" attribute theme={"system"} { "id": { ... }, "title": "Team", "api_slug": "team", "type": "record-reference", "config": { "record_reference": { "allowed_object_ids": [ "4e71c40b-7d35-463c-afcb-e339cfd6dbd1" ] } }, ... } ``` ### Reading values Record reference values have two properties, `target_object` (the `api_slug` representing what kind of object it is) and `target_record_id` (the ID of the Record). ```json A reference to person@company.com theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "record-reference", "target_object": "people", "target_record_id": "891dcbfc-9141-415d-9b2a-2238a6cc012d" } ``` ### Writing values There are multiple ways to write a record reference. Since it's such a common operation, Attio provides special write functionality if the record reference only allows a single object and that object is one of our standard objects: * If the allowed object is a company, you can use the `domains` attribute. * If the allowed object is a person, you can use the `email_addresses` attribute. * If the allowed object is a user, you can use the `user_id` attribute. * If the allowed object is a workspace, you can use the `workspace_id` attribute. ```json Referencing a company theme={"system"} { "associated_company": [ { "domains": [{"domain": "company.com"}], "target_object": "companies" } ] } ``` ```json Referencing a person theme={"system"} { "team": [ { "email_addresses": [{"email_address": "[email protected]"}], "target_object": "people" } ] } ``` ```json Referencing a user theme={"system"} { "user": [ { "user_id": [{"value": "my-user-id"}], "target_object": "users" } ] } ``` ```json Referencing a workspace theme={"system"} { "workspace": [ { "workspace_id": [{"value": "my-workspace-id"}], "target_object": "workspaces" } ] } ``` Furthermore, we allow writing to these attributes using string values. * If the allowed object is a company, string values will be interpreted as a domain. * If the allowed object is a person, string values will be interpreted as email addresses. * If the allowed object is a user, string values will be interpreted as `user_id` text values. * If the allowed object is a workspace, string values will be interpreted as `workspace_id` text values. ```json Domain theme={"system"} { "associated_company": "company.com" } ``` ```json Domains theme={"system"} { "associated_company": ["company.com", "company.net"] } ``` ```json Email theme={"system"} { "team": ["[email protected]"] } ``` ```json Email theme={"system"} { "team": ["[email protected]", "[email protected]"] } ``` ```json User theme={"system"} { "user": "my-user-id" } ``` ```json Users theme={"system"} { "user": ["my-user-id", "another-user-id"] } ``` ```json Workspace theme={"system"} { "workspace": "my-workspace-id" } ``` ```json Workspaces theme={"system"} { "workspace": ["my-workspace-id", "another-workspace-id"] } ``` If the attribute is multiselect ("many"), you can also pass these as a series of values like so: It's also possible to write record references using record IDs. ```json Using record IDs theme={"system"} { "associated_company": [ { "target_record_id": "99a03ff3-0435-47da-95cc-76b2caeb4dab", "target_object": "companies" } ] } ``` Note that the write will fail if the target record does not exist, i.e. you can't create the target record automatically. For example, if you tried to assert a person and referenced a company that did not exist, the request would fail. This means that you need to do your writes in reverse-order, e.g. starting with the company that the person is linked to, then creating the person. ### Filtering Record reference values can be filtered by `target_object` and `target_record_id` using exact equality matches. ```json Find people with a given company theme={"system"} { "filter": { "company": { "target_object": "companies", "target_record_id": "99a03ff3-0435-47da-95cc-76b2caeb4dab" } } } ``` ```json Find workspaces with a given user theme={"system"} { "filter": { "users": { "target_object": "97052eb9-e65e-443f-a297-f2d9a4a7f795", "target_record_id": "5e3fb280-007b-495a-a530-9354bde01de1" } } } ``` As well as exact equality matches, record reference values also support the `$in` operator. ```json Find people where their company's record_id is one of several possible values theme={"system"} { "filter": { "company": { "target_object": "companies", "target_record_id": { "$in": [ "3aeb39cd-fed8-524e-94b8-1300549354ac", "8c5cd602-1297-45d2-a99c-14ae091cbac3" ] } } } } ``` Record references are special, because they are also filterable using "paths", also known as "drill-downs". You can filter records based on attributes of the target records. `paths` is an array containing tuples of `(object type, attribute slug or ID)`, while `constraints` are applied to the attribute identified by the final path element. For example, we could construct a filter like "find me Companies which have an employee named John": ```json Companies with an employee named John theme={"system"} { "filter": { "path": [ ["companies", "team"], ["people", "name"] ], "constraints": { "first_name": { "$eq": "John" } } } } ``` Here, we're using the `team` attribute on a Company, which is a multi-select record reference to the person record. We then look across at those related `people`, and their `name` attribute values. Finally, since `name` is a [(personal) name](/docs/attribute-types/attribute-types-personal-name) attribute, we can query against the `first_name` property. Paths can be more complex, and even somewhat recursive. For example, if you had a `manager` attribute on the Person object, and it pointed to another Person, you could find people by who their manager's manager's manager was: ```json People by their manager's manager's manager theme={"system"} { "filter": { "path": [ ["people", "manager"], ["people", "manager"], ], "constraints": { "target_object": "people", "target_record_id": "managers-manager-id" } } } ``` # Select Source: https://docs.attio.com/docs/attribute-types/attribute-types-select An option from a predefined list Select attributes are a constrained input type, where the user must pick from a predefined list. Company has several select attributes (they are mostly [enriched attributes](https://attio.com/help/reference/data-and-syncing/enriched-data)): `categories`, `estimated_arr_usd` and `employee_range`. `strongest_connection_strength` is also available on both person and company. Attio provides a [separate API for managing the select options available](/rest-api/endpoint-reference/attributes/list-select-options). Select attributes may be either single-select or multi-select. In the API, these two variants are represented using the same underlying type, select. However, in web and mobile clients, users will see these attributes as two separate types: select and multi-select. Please note that select attributes cannot be configured to be unique. ### Reading values Select attribute values have an `option` property, which is an object describing which select option was used: ```json Example: 3 out of 5 stars theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "select", "option": { "id": { "workspace_id": "4f9a01be-3792-4ab9-926f-ca7f9005700c", "object_id": "5f1feef5-fe73-4c0e-9d97-5b0a96a7d32b", "attribute_id": "a4977b52-d367-4e28-a671-b5c4fa401fc5", "option_id": "14938464-cae9-4e50-8856-0fb584844f24" }, "title": "Aerospace & Defense", "is_archived": false } } ``` ### Writing values You can find a list of available options using the [list select options](/rest-api/endpoint-reference/attributes/list-select-options) API. To write select values, pass the title of the select option as a string. If it's a multi-value select attribute, you'll need to pass an array. You can also pass an object with an `option` property, which references either the `option_id` or the `title` of the select option. If you attempt to write a value where the ID or title cannot be found, you will receive an error rather than create a new select option. ```json Using string theme={"system"} { "categories": ["3D Printing"] } ``` ```json Multiple values theme={"system"} { "categories": ["3D Printing", "Architecture"] } ``` ```json Using object (title) theme={"system"} { "categories": [ { "option": "3D Printing" } ] } ``` ```json Using object (option_id) theme={"system"} { "categories": [ { "option": "14938464-cae9-4e50-8856-0fb584844f24" } ] } ``` ### Filtering Select attributes can be filtered by equality, using either the implicit syntax or the explicit one: ```json Finding companies in the "Aerospace & Defense" category theme={"system"} { "filter": { "categories": "Aerospace & Defense" } } ``` ```json ... with an option ID instead theme={"system"} { "filter": { "categories": { "option": { "$eq": "Aerospace & Defense" } } } } ``` It's also possible to use `$or` to find records which match one of several categories: ```json Find Companies in one of many categories theme={"system"} { "filter": { "$or": [ {"categories": "Aerospace & Defense"}, {"categories": "Biotechnology"} ] } } ``` Select attributes can also be filtered based on when they were modified, using the `active_from` property. This allows automations based on when the attribute was changed. This filter supports the `$lt`, `$lte`, `$gt`, `$gte` operators: ```json Finding companies where the category was changed this week theme={"system"} { "filter": { "categories": { "active_from": { "$gte": "2023-11-20" } } } } ``` ```json ... where the category was not changed this year theme={"system"} { "filter": { "categories": { "active_from": { "$lt": "2023-01-01" } } } } ``` # Status Source: https://docs.attio.com/docs/attribute-types/attribute-types-status Similar to select attributes, originally designed for use in Lists Just like [select](/docs/attribute-types/attribute-types-select) attributes, status attributes are a constrained input type, where the user must pick from a predefined list. They are used in the Attio UI to define the different columns on a kanban board, but they can also be used with objects directly. There's only one predefined status attribute, available on the deal object as `stage`. The possible values of a status attribute are known as "statuses", and there are [separate APIs for managing them](/rest-api/endpoint-reference/attributes/list-statuses). All status attributes are single-select. ### Reading values Status values have a `status` property, which is an object describing which status was used: ```json Example: 3 out of 5 stars theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "select", "status": { "id": { "workspace_id": "4f9a01be-3792-4ab9-926f-ca7f9005700c", "object_id": "5f1feef5-fe73-4c0e-9d97-5b0a96a7d32b", "attribute_id": "a4977b52-d367-4e28-a671-b5c4fa401fc5", "status_id": "11f07f01-c10f-4e05-a522-33e050bc52ee" }, "title": "In Progress", "is_archived": false, "target_time_in_status": null, "celebration_enabled": false } } ``` ### Writing values You can find a list of available statuses using the [list statuses](/rest-api/endpoint-reference/attributes/list-statuses) API. To write status values, pass the title of the status as a string. You can also pass an object with a `status` property which references either the `status_id` or the `title` of the status. If you attempt to write a value where the ID or title cannot be found, you will receive an error rather than create a new status. ```json Using string theme={"system"} { "stage": "Lead" } ``` ```json Using object (title) theme={"system"} { "stage": [ { "status": "Lead" } ] } ``` ```json Using object (status_id) theme={"system"} { "stage": [ { "status": "11f07f01-c10f-4e05-a522-33e050bc52ee" } ] } ``` ### Filtering Status attributes can be filtered by equality, using either the implicit syntax or the explicit one, with either the title or status ID: ```json Finding deals in the "In Progress" stage theme={"system"} { "filter": { "stage": "In Progress" } } ``` ```json ... with a status ID instead theme={"system"} { "filter": { "stage": { "status": { "$eq": "11f07f01-c10f-4e05-a522-33e050bc52ee" } } } } ``` You can also filter for multiple possible matching values using the `$or` syntax: ```json Finding deals in either "In Progress" or "Lead" stage theme={"system"} { "filter": { "$or": [ {"stage": "In Progress"}, {"stage": "Lead"} ] } } ``` Status attributes can also be filtered based on when they were modified, using the `active_from` property. This allows automations based on when the attribute was changed. This filter supports the `$lt`, `$lte`, `$gt`, `$gte` operators: ```json Finding deals where the stage was changed this week theme={"system"} { "filter": { "stage": { "active_from": { "$gte": "2023-11-20" } } } } ``` ```json ... where the stage was not changed this year theme={"system"} { "filter": { "stage": { "active_from": { "$lt": "2023-01-01" } } } } ``` # Text Source: https://docs.attio.com/docs/attribute-types/attribute-types-text Human-readable, unconstrained text inputs Text attributes are the most common type of attribute, and usually represent unstructured or human-readable data. They have a max size of 10mb. Examples of text attributes include the `description`, `facebook` or `instagram` attributes on company and person, or the `workspace_id` and `user_id` attributes on workspace/user. Please note that on person, the `name` attribute is a [(Personal) name](/docs/attribute-types/attribute-types-personal-name) attribute, but on company it's a text attribute. Text attributes are always single-select. ### Reading values Text attribute values have a single `value` property: ```json Example: 14 Twitter followers theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "text", "value": "A long time ago in a galaxy far, far away..." } ``` ### Writing values To write text attribute values, simply pass the string that you would like to set. You may also pass an object with a single `value` property. ```json Using string theme={"system"} { "description": "Headquartered in New York City, Waystar Royco was founded by Logan Roy and operates in 50 countries across 4 continents" } ``` ```json Using object theme={"system"} { "description": [ { "value": "Headquartered in New York City, Waystar Royco was founded by Logan Roy and operates in 50 countries across 4 continents" } ] } ``` ### Filtering Text can be filtered by the operators `$eq`, `$in`, `$contains`, `$starts_with` and `$ends_with`. The implicit syntax does an exact equality (`$eq`) check: ```json Finding companies with an exact description theme={"system"} { "filter": { "description": "An exact match" } } ``` ```json ... which starts with a prefix theme={"system"} { "filter": { "description": { "value": { "$starts_with": "Headquartered in New York City" } } } } ``` ```json ... which contains a keyword theme={"system"} { "filter": { "description": { "value": { "$contains": "New York City" } } } } ``` ```json ...where record_id is one of supplied values theme={"system"} { "filter": { "record_id": { "$in": ["000e8881-37cc-41d2-bc22-39fe35e76e6b", "592dc9d8-548b-4148-813f-1259055ca83c"] } } } ``` # Timestamp Source: https://docs.attio.com/docs/attribute-types/attribute-types-timestamp A calendar date including time information, stored in UTC Timestamp attributes represent a single, universal moment in time using the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format. Time information is stored with nanosecond precision, and UTC is the assumed timezone if one is not provided. Timestamp values will always be returned in UTC. Every Attio object has a `created_at` timestamp attribute, but users can also create their own custom timestamp attributes. All timestamp attributes are single-select. ### Reading values Timestamp attributes have a single property, `value` (string). ```json Example: 24th November, 2023 theme={"system"} { "active_from": "2023-04-03T15:21:06.447000000Z", "active_until": null, "created_by_actor": {...}, "attribute_type": "date", "value": "2023-11-24T15:17:48.000000000Z" } ``` ### Writing values Input values will be coerced into the full format. UTC is assumed if not specified. For example, the following input values would all be coerced to `"2023-01-02T13:00:00.000000000Z"`: * `"2023"` * `"2023-01"` * `"2023-01-02"` * `"2023-01-02T13:00"` * `"2023-01-02T13:00:00"` * `"2023-01-02T13:00:00.000000000"` * `"2023-01-02T15:00:00.000000000+02:00` To write timestamp attribute values, you should specify the `value` property: You may also pass an object with a single property, `value`. ```Text Using string theme={"system"} { "my_timestamp_attribute": "2019-01-17T15:17:48.000000000Z" } ``` ```json Using object theme={"system"} { "my_timestamp_attribute": [ { "value": "2019-01-17T15:17:48.000000000Z" } ] } ``` ### Filtering Timestamp attribute values can be filtered by their value. Unlike when writing timestamp values, both date and time components must be specified. You can filter for an exact timestamp using the implicit syntax, or use the `$eq`,`$gt`,`$gte`,`$lt`,`$lte` operators with the explicit syntax. ```json Companies created on 2023-11-24 at 15:34:07.111222333Z theme={"system"} { "filter": { "created_at": "2023-11-24T15:34:07.111222333Z" } } ``` ```json ... after the year 2000 theme={"system"} { "filter": { "created_at": { "value": { "$gte": "2000-01-01T00:00:00Z" } } } } ``` Since timestamps are stored with nanosecond precision, it is often undesirable to look for an exact timestamp if you're trying to filter records with a lower precision, e.g. in a given hour or day. Here, you should use two operators to set the upper and lower bounds of the query, remembering to use the inclusive `$gte` for the earlier bound and the exclusive `$lt` for the upper bound: ```json Companies created between 8am and 9am theme={"system"} { "filter": { "created_at": { "$gte": "2023-11-24T08:00:00Z", "$lt": "2023-11-24T09:00:00Z" } } } ``` ```json ... on 24th November theme={"system"} { "filter": { "created_at": { "$gte": "2023-11-24T00:00:00Z", "$lt": "2023-11-25T00:00:00Z" } } } ``` # Default values Source: https://docs.attio.com/docs/default-values Attribute definitions on objects and lists support default values which are used to pre-populate values on records and entries. There are two kinds of default value: static and dynamic. ## Static defaults Static values are raw values that are used directly without transformation. For example, you might want to always fill the “Deal Status” property on new entries in your “Sales” list to the value “Lead”. Static values are supported on all attribute types. The `template` property on default values must match the type of the attribute. These types are documented in our endpoint reference docs. ## Dynamic defaults Dynamic values are used to generate values on the fly, depending on context. For example, you might want to fill in an “Owner” property to the current user, or set a due date to one week in the future. Dynamic values take the form of a string. The currently supported list of dynamic value templates, broken down by attribute type, is as follows: * `actor-reference` attributes, with the default value `current-user` * `timestamp` or `date` attributes, with an [ISO 8601 Duration](https://tc39.es/proposal-temporal/docs/duration.html) e.g. `“P1M”` for one month in the future Other attribute types do not currently support dynamic default values. # Authorize Source: https://docs.attio.com/docs/oauth/authorize GET https://app.attio.com/authorize ## Query Parameters Your app's client ID. You can find this in your app's settings pages at [build.attio.com](https://build.attio.com). The response type. This should always be `"code"`. The URL to redirect to after the user authorizes access to your app. This URL must exactly match one of the registered redirect URLs in your app's settings pages at [build.attio.com](https://build.attio.com). A random string to prevent CSRF attacks. Set this when starting the OAuth flow and verify it matches when the user is redirected back to your app. ## Response After the user approves the connection, they are redirected to the `redirect_uri` with a `code` query parameter. If provided, the original `state` is also included. # Introspect Source: https://docs.attio.com/docs/oauth/introspect POST https://app.attio.com/oauth/introspect Check whether an access token is valid, and if so, what scopes and identity it grants. A bearer token should be passed in the `Authorization` header of the request. ## Response ### Inactive Token Whether the token is currently active and usable. Returns `false` for invalid or expired tokens. ### Active Token Whether the token is currently active and usable. Returns `true` for valid tokens. A space-separated list of scopes associated with this token. The app ID of the OAuth app that requested this token. The type of token. Always `"Bearer"` for tokens acquired via the OAuth 2.0 flow. The time at which this token will expire, if set, as a number of seconds since January 1 1970 UTC. The time at which this token was issued, as a number of seconds since January 1 1970 UTC. Since Bearer tokens grant workspace-level permissions, this property contains the workspace ID. The intended audience for this token. For Bearer tokens this is the same as the `client_id`. The issuer of the token. Always `"attio.com"`. The ID of the workspace member who authorized this token initially. The ID of the workspace the token is scoped to. The name of the workspace the token is scoped to. The slug of the workspace the token is scoped to. The logo URL of the workspace the token is scoped to. # Token Source: https://docs.attio.com/docs/oauth/token POST https://app.attio.com/oauth/token ## Request Your app's client ID. You can find this in your app's settings pages at [build.attio.com](https://build.attio.com). Your app's client secret. You can find this in your app's settings pages at [build.attio.com](https://build.attio.com). The grant type. This should always be `"authorization_code"`. The code which you received after being redirected from the `/authorize` endpoint. ## Response An access token for the workspace which can be used to make authenticated requests to the Attio REST API. The type of token. Always `"Bearer"`. # Objects and lists Source: https://docs.attio.com/docs/objects-and-lists At the core of Attio is our powerful and flexible data model, which allows you to define custom objects and lists with a wide array of attribute types. Objects can be used to model your domain entities, while lists can be used to aggregate them together and model business processes. However, both objects and lists can have their own attributes. For example, you might be using the deal object to keep track of the various deals you have in progress, but you could also create a list of deals with some additional attributes only relevant to a deal in that list. ## Objects Objects are the data types used to store facts about your customer. By themselves, they contain little information other than a name, but records and attributes are scoped to a single object. Attio comes with two objects enabled by default, people and companies, and three optional objects: deal, user and workspace. In relational database terms, objects are roughly tables. In object-orientated terms, they are analogous to classes. Note that an instance of an object is called a record (see below). For more information about Attio objects, please [see our help center guide](https://attio.com/help/reference/workspace/objects). ### Records Records are an instantiation of an object, e.g. a specific person or a specific company. In relational database terms, a record is roughly a row in a table. In object-orientated terms, they are analogous to an object (an instantiated class). ### Attributes Attributes sit on objects and lists and describe what data we can store. Some attributes, such as the name on a person, are system defined. Others, you define yourself, either in Attio’s UI or over the API. Attributes are one of many types such as text, number, select, or currency. In relational database terms, an attribute is roughly a column in a table. ## Lists & entries Lists are composed of multiple rows, known as "entries", each of which corresponds to a single record. Entries are created by adding a record to a list. Lists can be used to model a particular process. For example, you might have a "Sales" list that contains the companies that you have relationships with. # Overview Source: https://docs.attio.com/docs/overview Start building Attio Apps Attio is a revolutionary CRM platform which is highly customisable, incredibly powerful and data-driven. In these guides, you can find everything you need to build powerful integrations, automations and data pipelines on top of Attio. Our docs cover guides, examples, references and code to help you build apps and share them with Attio's customers or for your own workspace. The Attio Developer Platform consists of two parts: This allows developers to embed Typescript React applications within the Attio interface and run server functions with access to our REST API. This allows developers to build apps that read and write information to and from Attio workspaces. You can also subscribe to events in realtime using webhooks. You can use both the App SDK and REST API in your app to build rich experiences. # Slugs and IDs Source: https://docs.attio.com/docs/slugs-and-ids Attio uses [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier) (universally unique identifiers) to identify most of the objects in our system. We can also identify many API objects by their slug property. Slugs have the advantage that they are human-readable. For standard objects and attributes, slugs are also consistent across workspaces. ## IDs and Uniqueness Entities returned from Attio’s API contain an `id` property which is composed of one or more sub-IDs. The sub-IDs are each a UUID that identifies either the entity or one of its parents. ```json Example ID from a record response theme={"system"} { "data": { "id": { "workspace_id": "5821c091-cf04-4aab-a72a-f1646dbd6841", "object_id": "7c430b6d-fa5b-48c6-bfa7-9520c088c7bc", "record_id": "d2c2f990-3af0-4be5-808a-5605549e787f" }, // ... } } ``` Uniqueness of an ID is only guaranteed when the ID is taken as a whole, using all sub-IDs. For example, it is unsafe to assume in the example above that the record is the only record with `record_id=”d2c2f990-3af0-4be5-808a-5605549e787f”`. The safe assumption is that the record is the only record with `record_id=”d2c2f990-3af0-4be5-808a-5605549e787f”` *and* `object_id=”7c430b6d-fa5b-48c6-bfa7-9520c088c7bc"` *and* `workspace_id="5821c091-cf04-4aab-a72a-f1646dbd6841"`. In practice, such collisions will be rare, but they are important to bear in mind. This is especially true if you are building large integrations which operate on the data of many workspaces. If you are only operating on data from your own workspace, you can essentially disregard the `workspace_id` key. ## Slugs For ergonomics and readability, Attio’s API utilises slugs across a variety of entities such as list, objects and attributes. Path parameters, query parameters, request bodies and responses will utilise a unique slug instead of an ID where appropriate. For example, a request to the [create record endpoint](/rest-api/endpoint-reference/records/create-a-record) accepts values keyed by either the attribute slug or attribute ID and returns values keyed by slug. ```json Request theme={"system"} // Slug form { "data": { "values": { "email_addresses": [ { "email_address": "[email protected]" } ] } // other values... } } // ID form { "data": { "values": { "8a8ad54f-9314-4bdb-b867-e62d02a7d333": [ { "email_address": "[email protected]" } ] } // other values... } } ``` ```json Response theme={"system"} { "data": { "values": { "email_addresses": [ { "active_from": "2023-06-01T15:49:08.524000000Z", "active_until": null, "created_by_actor": { "type": "api-token", "id": "d475d597-2900-4c93-841c-9f83154f21dc" }, "original_email_address": "[email protected]", "email_address": "[email protected]", "email_domain": "bell-labs.com", "email_root_domain": "bell-labs.com", "email_local_specifier": "r.hamming", "attribute_type": "email-address" } ] // other values... } // other properties on data... } } ``` Slugs are set explicitly over the API, or created automatically when entities are created through the UI. Slugs are not updated when entities are renamed through the UI, so they can be reliably used once seen. They are always unique across entities. For example, there cannot be two attributes with the same slug on the same list. Slugs of system attributes and objects are consistent across time and across workspaces. Non-system slugs are mutable, so care should be taken when modifying them in case they break any integrations relying upon them. If you would like to provide resilience against such changes, please use IDs when looking up objects instead. Slugs can be found on the following entities: * Object (`api_slug`) * Attribute (`api_slug`) * List (`api_slug`) * Status (`title`) * Select Option (`title`) *** # Overview Source: https://docs.attio.com/docs/standard-objects/standard-objects Companies and people are available in all workspaces Every Attio workspace starts with a company and person object, and admins can optionally enable the deal, user and workspace standard objects if it meets their needs. These 5 objects come with a pre-defined set of attributes. As a developer, you can rely on being able to read and write from/to these predefined (or "system") attributes. Admins can also add custom attributes to any of these objects, or create new custom objects with custom attributes on those. Developers can interact with both standard and custom objects in the same ways, using e.g. the [assert a Record](/rest-api/endpoint-reference/records/assert-a-record) API, but the following pages go into more detail about exactly which attributes you might find and how to read/write them for these. ## Attributes on every object | Attribute | Type | Writable? | Notes | | --------------------------------------------- | --------------- | --------- | ------------------------------------------------------------------------------------------------------- | | `created_at` | Timestamp | No | When the record was created, defaults to current timestamp (see [Default values](/docs/default-values)) | | `created_by` (which actor created the record) | Actor reference | No | Which actor created the record, defaults to current user in web application, or the integration in API | | `record_id` | Text (UUID) | No | The unique identifier for the record, available as an attribute value to allow easy querying | # Companies Source: https://docs.attio.com/docs/standard-objects/standard-objects-companies An object to represent businesses: customers, partners, peers... ```yaml Company configuration theme={"system"} api_slug: companies singular_noun: Company plural_noun: Companies ``` The company object is available in every Attio workspace. Companies represent businesses, such as customers, partners, suppliers, etc. When creating a person, a related company record will automatically be generated or matched based on the domain of the person's email address, but they can also be created manually via the web application or the API. Company records are enriched, which means that Attio will automatically populate additional attributes, and those enriched values cannot be overridden by API users. Additionally, some enriched attributes may be hidden from the API depending on the workspace billing plan. ## Writable attributes The following attributes can always be read and written using the API: | Attribute | Slug | Type | Traits | | --------------------- | ----------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | Domains | `domains` | [Domain](/docs/attribute-types/attribute-types-domain) | Unique, multiselect | | Name | `name` | [Text](/docs/attribute-types/attribute-types-text) | | | Description | `description` | [Text](/docs/attribute-types/attribute-types-text) | | | Team | `team` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Person -> company`, multiselect | | Categories | `categories` | [Select](/docs/attribute-types/attribute-types-select) | Multiselect | | Primary location | `primary_location` | [Location](/docs/attribute-types/attribute-types-location) | | | AngelList | `angellist` | [Text](/docs/attribute-types/attribute-types-text) | | | Facebook | `facebook` | [Text](/docs/attribute-types/attribute-types-text) | | | Instagram | `instagram` | [Text](/docs/attribute-types/attribute-types-text) | | | LinkedIn | `linkedin` | [Text](/docs/attribute-types/attribute-types-text) | | | Twitter | `twitter` | [Text](/docs/attribute-types/attribute-types-text) | | | Associated deals | `associated_deals` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Deal -> associated_companies` (only visible if [Deals](/docs/standard-objects/standard-objects-deals) activated | | Associated workspaces | `associated_workspaces` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Workspace -> company` (only visible if [Workspaces](/docs/standard-objects/standard-objects-workspaces) activated) | It's important to note that while standard attributes like `domains` have unique properties by default, you cannot create new custom attributes with a unique constraint for Company objects. # Deals Source: https://docs.attio.com/docs/standard-objects/standard-objects-deals An object to represent deals involving people & companies ```yaml Deal configuration theme={"system"} api_slug: deals singular_noun: Deal plural_noun: Deal ``` The Deal object is available in every Attio workspace, but disabled by default. It can only be activated by a workspace admin, in the [objects settings](https://app.attio.com/_/settings/data/objects) page. ## Writeable attributes | Attribute | Slug | Type | Traits | | ------------------ | -------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | Name | `name` | [Text](/docs/attribute-types/attribute-types-text) | Required | | Deal stage | `stage` | [Status](/docs/attribute-types/attribute-types-status) | Required - by default one of `"Lead"`, `"In Progress"`, `"Won 🎉"`, `"Lost"` (workspaces can configure these status options) | | Deal owner | `owner` | [Actor reference](/docs/attribute-types/attribute-types-actor-reference) | Required | | Deal value | `value` | [Currency](/docs/attribute-types/attribute-types-currency) | Defaults to USD, can be changed | | Associated people | `associated_people` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Person -> associated_deals` | | Associated company | `associated_company` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Company -> associated_deals` | Note that deals do not have a unique attribute by default. This means that they cannot be automatically asserted without adding an additional unique attribute. # People Source: https://docs.attio.com/docs/standard-objects/standard-objects-people An object to represent human beings ```yaml People configuration theme={"system"} api_slug: people singular_noun: Person plural_noun: People ``` The person object is available in every Attio workspace. When creating a person, a related company record will automatically be generated or matched based on the domain of the person's email address, but they can also be created manually via the web application or the API. Person records are enriched, which means that Attio will automatically populate additional attributes, and those values cannot be overridden by API users. Additionally, some enriched attributes may be hidden from the API depending on the workspace billing plan. ## Writeable attributes | Attribute | Slug | Type | Traits | | ---------------- | ------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | Email addresses | `email_addresses` | [Email address](/docs/attribute-types/attribute-types-email-address) | Unique, multiselect | | Name | `name` | [(Personal) name](/docs/attribute-types/attribute-types-personal-name) | | | Company | `company` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Company -> team` | | Description | `description` | [Text](/docs/attribute-types/attribute-types-text) | | | Job title | `job_title` | [Text](/docs/attribute-types/attribute-types-text) | | | Phone numbers | `phone_numbers` | [Phone number](/docs/attribute-types/attribute-types-phone-number) | Multiselect | | Primary location | `primary_location` | [Location](/docs/attribute-types/attribute-types-location) | | | AngelList | `angellist` | [Text](/docs/attribute-types/attribute-types-text) | | | Facebook | `facebook` | [Text](/docs/attribute-types/attribute-types-text) | | | Instagram | `instagram` | [Text](/docs/attribute-types/attribute-types-text) | | | LinkedIn | `linkedin` | [Text](/docs/attribute-types/attribute-types-text) | | | Twitter | `twitter` | [Text](/docs/attribute-types/attribute-types-text) | | | Associated deals | `associated_deals` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Deal -> associated_people` (only available if [Deals](/docs/standard-objects/standard-objects-deals) activated) | | Associated users | `associated_users` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `User -> person` (only available if [Users](/docs/standard-objects/standard-objects-users) activated) | # Users Source: https://docs.attio.com/docs/standard-objects/standard-objects-users An object to represent users of your product ```yaml User configuration theme={"system"} api_slug: users singular_noun: User plural_noun: Users ``` The User object is available in every Attio workspace, but disabled by default. It can only be activated by a workspace admin, in the [Objects settings](https://app.attio.com/_/settings/data/objects) page. Users represent a user of your product. They are related to a [Person](/docs/standard-objects/standard-objects-people), have an email address, and an ID attribute that is defined by your system. Users are grouped together in Workspaces. ## Writeable attributes | Attribute | Slug | Type | Traits | | --------------------- | ----------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------- | | Person | `person` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Person -> associated_users` | | Primary email address | `primary_email_address` | [Text](/docs/attribute-types/attribute-types-text) | Required, unique - this is usually their login email in your system | | ID | `user_id` | [Text](/docs/attribute-types/attribute-types-text) | Required, unique - this is usually their ID in your system | | Workspaces | `workspace` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Workspace -> users` | Users can be asserted by either their `primary_email_address` or `user_id` unique attributes, or you can add your own. # Workspaces Source: https://docs.attio.com/docs/standard-objects/standard-objects-workspaces An object to group users of your product ```yaml Workspace configuration theme={"system"} api_slug: workspaces singular_noun: Workspace plural_noun: Workspaces ``` The Workspace object is available in every Attio workspace, but disabled by default. It can only be activated by a workspace admin, in the [objects settings](https://app.attio.com/_/settings/data/objects) page. Workspaces represent a grouping of users, or an account, in your product. Workspaces can belong to a [company](/docs/standard-objects/standard-objects-companies) and have multiple [users](/docs/standard-objects/standard-objects-users). ## Writeable attributes | Attribute | Slug | Type | Traits | | ---------- | -------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | ID | `workspace_id` | [Text](/docs/attribute-types/attribute-types-text) | Unique, required | | Name | `name` | [Text](/docs/attribute-types/attribute-types-text) | | | Users | `users` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `User -> workspaces`, multiselect | | Company | `company` | [Record reference](/docs/attribute-types/attribute-types-record-reference) | Relationship, inverse of `Company -> associated_workspaces` | | Avatar URL | `avatar_url` | [Text](/docs/attribute-types/attribute-types-text) | Similar to [Company](/docs/standard-objects/standard-objects-companies) `logo_url` | Workspaces have a single unique attribute, `workspace_id`, which can be used for assertions, or you can add your own. # Users and workspaces Source: https://docs.attio.com/docs/users-and-workspaces *Not to be confused with our standard objects [users](/docs/standard-objects/standard-objects-users) and [workspaces](/docs/standard-objects/standard-objects-workspaces)* A **user** is a login account with Attio. For example, a person who has signed up to Attio with the email `person@company.com`. A **workspace** is a company account with objects, records, lists and such. Every user has at least one workspace created when signing up for the first time. Some users will have multiple workspaces when they are members of large orgsharanisations with multiple workspaces, or for testing and development purposes. Since users can join multiple workspaces, we use the **workspace member** concept to represent a single user in a single workspace (this also encapsulates their permissions, such as whether they are an admin). All access to the Attio API is scoped to a single workspace, so you will never interact with users directly. Instead, user-level data such as email addresses are accessed through [workspace member APIs](/rest-api/endpoint-reference/workspace-members/list-workspace-members). # Create a select option Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/create-a-select-option https://api.attio.com/openapi/api post /v2/{target}/{identifier}/attributes/{attribute}/options Adds a select option to a select attribute on an object or a list. Required scopes: `object_configuration:read-write`. # Create a status Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/create-a-status https://api.attio.com/openapi/api post /v2/{target}/{identifier}/attributes/{attribute}/statuses Add a new status to a status attribute on either an object or a list. Required scopes: `object_configuration:read-write`. # Create an attribute Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/create-an-attribute https://api.attio.com/openapi/api post /v2/{target}/{identifier}/attributes Creates a new attribute on either an object or a list. To create an attribute on an object, you must also have the `object_configuration:read-write` scope. To create an attribute on a list, you must also have the `list_configuration:read-write` scope. # Get an attribute Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/get-an-attribute https://api.attio.com/openapi/api get /v2/{target}/{identifier}/attributes/{attribute} Gets information about a single attribute on either an object or a list. Required scopes: `object_configuration:read`. # List attributes Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/list-attributes https://api.attio.com/openapi/api get /v2/{target}/{identifier}/attributes Lists all attributes defined on a specific object or list. Attributes are returned in the order that they are sorted by in the UI. Required scopes: `object_configuration:read`. # List select options Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/list-select-options https://api.attio.com/openapi/api get /v2/{target}/{identifier}/attributes/{attribute}/options Lists all select options for a particular attribute on either an object or a list. Required scopes: `object_configuration:read`. # List statuses Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/list-statuses https://api.attio.com/openapi/api get /v2/{target}/{identifier}/attributes/{attribute}/statuses Lists all statuses for a particular status attribute on either an object or a list. Required scopes: `object_configuration:read`. # Update a select option Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/update-a-select-option https://api.attio.com/openapi/api patch /v2/{target}/{identifier}/attributes/{attribute}/options/{option} Updates a select option on an attribute on either an object or a list. Required scopes: `object_configuration:read-write`. # Update a status Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/update-a-status https://api.attio.com/openapi/api patch /v2/{target}/{identifier}/attributes/{attribute}/statuses/{status} Update a status on an status attribute on either an object or a list. Required scopes: `object_configuration:read-write`. # Update an attribute Source: https://docs.attio.com/rest-api/endpoint-reference/attributes/update-an-attribute https://api.attio.com/openapi/api patch /v2/{target}/{identifier}/attributes/{attribute} Updates a single attribute on a given object or list. Required scopes: `object_configuration:read-write`. # Get call recording Source: https://docs.attio.com/rest-api/endpoint-reference/call-recordings/get-call-recording https://api.attio.com/openapi/api get /v2/meetings/{meeting_id}/call_recordings/{call_recording_id} Get a single call recording by ID. This endpoint is in beta. We will aim to avoid breaking changes, but small updates may be made as we roll out to more users. Required scopes: `meeting:read`, `call_recording:read`. # List call recordings Source: https://docs.attio.com/rest-api/endpoint-reference/call-recordings/list-call-recordings https://api.attio.com/openapi/api get /v2/meetings/{meeting_id}/call_recordings List all call recordings for a meeting. This endpoint is in beta. We will aim to avoid breaking changes, but small updates may be made as we roll out to more users. Required scopes: `meeting:read`, `call_recording:read`. # Create a comment Source: https://docs.attio.com/rest-api/endpoint-reference/comments/create-a-comment https://api.attio.com/openapi/api post /v2/comments Creates a new comment related to an existing thread, record or entry. To create comments on records, you will need the `object_configuration:read` and `record_permission:read` scopes. To create comments on list entries, you will need the `list_configuration:read` and `list_entry:read` scopes. Required scopes: `comment:read-write`. # Delete a comment Source: https://docs.attio.com/rest-api/endpoint-reference/comments/delete-a-comment https://api.attio.com/openapi/api delete /v2/comments/{comment_id} Deletes a comment by ID. If deleting a comment at the head of a thread, all messages in the thread are also deleted. Required scopes: `comment:read-write`. # Get a comment Source: https://docs.attio.com/rest-api/endpoint-reference/comments/get-a-comment https://api.attio.com/openapi/api get /v2/comments/{comment_id} Get a single comment by ID. To view comments on records, you will need the `object_configuration:read` and `record_permission:read` scopes. To view comments on list entries, you will need the `list_configuration:read` and `list_entry:read` scopes. Required scopes: `comment:read`. # Assert a company record Source: https://docs.attio.com/rest-api/endpoint-reference/companies/assert-a-company-record https://api.attio.com/openapi/standard-objects put /v2/objects/companies/records Use this endpoint to create or update company records, using a unique attribute to search for existing companies (for example, the `domains` attribute). If a company is found with the same value for the matching attribute, that company will be updated. If no company with the same value for the matching attribute is found, a new company will be created instead. If you would like to avoid matching, please use the Create company endpoint. If the matching attribute is a multiselect attribute, new values will be added and existing values will not be deleted. For any other multiselect attribute, all values will be either created or deleted as necessary to match the list of supplied values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a company record Source: https://docs.attio.com/rest-api/endpoint-reference/companies/create-a-company-record https://api.attio.com/openapi/standard-objects post /v2/objects/companies/records Creates a new company record. This endpoint will throw on conflicts of unique attributes, like `domains`. If you would prefer to update company records on conflicts, please use the Assert company record endpoint instead. Please note, the `logo_url` attribute cannot currently be set via the API. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Delete a company record Source: https://docs.attio.com/rest-api/endpoint-reference/companies/delete-a-company-record https://api.attio.com/openapi/standard-objects delete /v2/objects/companies/records/{record_id} Deletes a single company record by ID. Required scopes: `object_configuration:read`, `record_permission:read-write`. # Get a company record Source: https://docs.attio.com/rest-api/endpoint-reference/companies/get-a-company-record https://api.attio.com/openapi/standard-objects get /v2/objects/companies/records/{record_id} Gets a single company record by its `record_id`. Required scopes: `record_permission:read`, `object_configuration:read`. # List company record attribute values Source: https://docs.attio.com/rest-api/endpoint-reference/companies/list-company-record-attribute-values https://api.attio.com/openapi/standard-objects get /v2/objects/companies/records/{record_id}/attributes/{attribute}/values Gets all values for a given attribute on a company record. Historic values can be queried using the `show_historic` query param. Historic values cannot be queried on COMINT (Communication Intelligence) or enriched attributes and the endpoint will return a 400 error if this is attempted. Historic values are sorted from oldest to newest (by `active_from`). Some attributes are subject to billing status and will return an empty array of values if theworkspace being queried does not have the required billing flag enabled. Required scopes: `record_permission:read`, `object_configuration:read`. # List company record entries Source: https://docs.attio.com/rest-api/endpoint-reference/companies/list-company-record-entries https://api.attio.com/openapi/standard-objects get /v2/objects/companies/records/{record_id}/entries List all entries, across all lists, for which this company record is the parent. Required scopes: `record_permission:read`, `object_configuration:read`, `list_entry:read`. # List company records Source: https://docs.attio.com/rest-api/endpoint-reference/companies/list-company-records https://api.attio.com/openapi/standard-objects post /v2/objects/companies/records/query Lists company records, with the option to filter and sort results. Required scopes: `record_permission:read`, `object_configuration:read`. # Update a company record Source: https://docs.attio.com/rest-api/endpoint-reference/companies/update-a-company-record https://api.attio.com/openapi/standard-objects patch /v2/objects/companies/records/{record_id} Use this endpoint to update company records by `record_id`. If the update payload includes multiselect attributes, the values supplied will be created and prepended to the list of values that already exist (if any). Use the [Assert company endpoint](/rest-api/endpoint-reference/standard-objects/companies/assert-a-company-record) to overwrite or remove multiselect attribute values. Please note, the `logo_url` attribute cannot currently be updated via the API. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Assert a deal record Source: https://docs.attio.com/rest-api/endpoint-reference/deals/assert-a-deal-record https://api.attio.com/openapi/standard-objects put /v2/objects/deals/records Use this endpoint to create or update deal records, using a unique attribute to search for existing deals. By default, deals do not have a unique attribute, so you should add your own attribute with a unique constraint to use this API. If a deal is found with the same value for the matching attribute, that deal will be updated, otherwise a new deal will be created instead. If the matching attribute is a multiselect attribute, new values will be added and existing values will not be deleted. For any other multiselect attribute, all values will be either created or deleted as necessary to match the list of supplied values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a deal record Source: https://docs.attio.com/rest-api/endpoint-reference/deals/create-a-deal-record https://api.attio.com/openapi/standard-objects post /v2/objects/deals/records Creates a new deal record. This endpoint will throw on conflicts of unique attributes, if defined. If you would prefer to update deal records on conflicts, please use the Assert deal record endpoint instead. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Delete a deal record Source: https://docs.attio.com/rest-api/endpoint-reference/deals/delete-a-deal-record https://api.attio.com/openapi/standard-objects delete /v2/objects/deals/records/{record_id} Deletes a single deal record by ID. Required scopes: `object_configuration:read`, `record_permission:read-write`. # Get a deal record Source: https://docs.attio.com/rest-api/endpoint-reference/deals/get-a-deal-record https://api.attio.com/openapi/standard-objects get /v2/objects/deals/records/{record_id} Gets a single deal record by its `record_id`. Required scopes: `record_permission:read`, `object_configuration:read`. # List deal record attribute values Source: https://docs.attio.com/rest-api/endpoint-reference/deals/list-deal-record-attribute-values https://api.attio.com/openapi/standard-objects get /v2/objects/deals/records/{record_id}/attributes/{attribute}/values Gets all values for a given attribute on a deal record. Historic values can be queried using the `show_historic` query param. Historic values are sorted from oldest to newest (by `active_from`). Required scopes: `record_permission:read`, `object_configuration:read`. # List deal record entries Source: https://docs.attio.com/rest-api/endpoint-reference/deals/list-deal-record-entries https://api.attio.com/openapi/standard-objects get /v2/objects/deals/records/{record_id}/entries List all entries, across all lists, for which this deal record is the parent. Required scopes: `record_permission:read`, `object_configuration:read`, `list_entry:read`. # List deal records Source: https://docs.attio.com/rest-api/endpoint-reference/deals/list-deal-records https://api.attio.com/openapi/standard-objects post /v2/objects/deals/records/query Lists deal records, with the option to filter and sort results. Required scopes: `record_permission:read`, `object_configuration:read`. # Update a deal record Source: https://docs.attio.com/rest-api/endpoint-reference/deals/update-a-deal-record https://api.attio.com/openapi/standard-objects patch /v2/objects/deals/records/{record_id} Use this endpoint to update deal records by `record_id`. If the update payload includes multiselect attributes, the values supplied will be created and prepended to the list of values that already exist (if any). Use the [Assert deal endpoint](/rest-api/endpoint-reference/standard-objects/deals/assert-a-deal-record) to overwrite or remove multiselect attribute values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Assert a list entry by parent Source: https://docs.attio.com/rest-api/endpoint-reference/entries/assert-a-list-entry-by-parent https://api.attio.com/openapi/api put /v2/lists/{list}/entries Use this endpoint to create or update a list entry for a given parent record. If an entry with the specified parent record is found, that entry will be updated. If no such entry is found, a new entry will be created instead. If there are multiple entries with the same parent record, this endpoint with return the "MULTIPLE_MATCH_RESULTS" error. When writing to multi-select attributes, all values will be either created or deleted as necessary to match the list of values supplied in the request body. Required scopes: `list_entry:read-write`, `list_configuration:read`. # Create an entry (add record to list) Source: https://docs.attio.com/rest-api/endpoint-reference/entries/create-an-entry-add-record-to-list https://api.attio.com/openapi/api post /v2/lists/{list}/entries Adds a record to a list as a new list entry. This endpoint will throw on conflicts of unique attributes. Multiple list entries are allowed for the same parent record Required scopes: `list_entry:read-write`, `list_configuration:read`. # Delete a list entry Source: https://docs.attio.com/rest-api/endpoint-reference/entries/delete-a-list-entry https://api.attio.com/openapi/api delete /v2/lists/{list}/entries/{entry_id} Deletes a single list entry by its `entry_id`. Required scopes: `list_entry:read-write`, `list_configuration:read`. # Get a list entry Source: https://docs.attio.com/rest-api/endpoint-reference/entries/get-a-list-entry https://api.attio.com/openapi/api get /v2/lists/{list}/entries/{entry_id} Gets a single list entry by its `entry_id`. Required scopes: `list_entry:read`, `list_configuration:read`. # List attribute values for a list entry Source: https://docs.attio.com/rest-api/endpoint-reference/entries/list-attribute-values-for-a-list-entry https://api.attio.com/openapi/api get /v2/lists/{list}/entries/{entry_id}/attributes/{attribute}/values Gets all values for a given attribute on a list entry. This endpoint has the ability to return all historic values using the `show_historic` query param. Historic values are sorted from oldest to newest (by `active_from`). Required scopes: `list_entry:read`, `list_configuration:read`. # List entries Source: https://docs.attio.com/rest-api/endpoint-reference/entries/list-entries https://api.attio.com/openapi/api post /v2/lists/{list}/entries/query Lists entries in a given list, with the option to filter and sort results. Required scopes: `list_entry:read`, `list_configuration:read`. # Update a list entry (append multiselect values) Source: https://docs.attio.com/rest-api/endpoint-reference/entries/update-a-list-entry-append-multiselect-values https://api.attio.com/openapi/api patch /v2/lists/{list}/entries/{entry_id} Use this endpoint to update list entries by `entry_id`. If the update payload includes multiselect attributes, the values supplied will be created and prepended to the list of values that already exist (if any). Use the `PUT` endpoint to overwrite or remove multiselect attribute values. Required scopes: `list_entry:read-write`, `list_configuration:read`. # Update a list entry (overwrite multiselect values) Source: https://docs.attio.com/rest-api/endpoint-reference/entries/update-a-list-entry-overwrite-multiselect-values https://api.attio.com/openapi/api put /v2/lists/{list}/entries/{entry_id} Use this endpoint to update list entries by `entry_id`. If the update payload includes multiselect attributes, the values supplied will overwrite/remove the list of values that already exist (if any). Use the `PATCH` endpoint to add multiselect attribute values without removing those value that already exist. Required scopes: `list_entry:read-write`, `list_configuration:read`. # Create a list Source: https://docs.attio.com/rest-api/endpoint-reference/lists/create-a-list https://api.attio.com/openapi/api post /v2/lists Creates a new list. Once you have your list, add attributes to it using the [Create attribute](/rest-api/endpoint-reference/attributes/create-an-attribute) API, and add records to it using the [Add records to list](/rest-api/endpoint-reference/entries/create-an-entry-add-record-to-list) API. New lists must specify which records can be added with the `parent_object` parameter which accepts either an object slug or an object ID. Permissions for the list are controlled with the `workspace_access` and `workspace_member_access` parameters. Please note that new lists must have either `workspace_access` set to `"full-access"` or one or more element of `workspace_member_access` with a `"full-access"` level. It is also possible to receive a `403` billing error if your workspace is not on a plan that supports either advanced workspace or workspace member-level access for lists. Required scopes: `list_configuration:read-write`. # Get a list Source: https://docs.attio.com/rest-api/endpoint-reference/lists/get-a-list https://api.attio.com/openapi/api get /v2/lists/{list} Gets a single list in your workspace that your access token has access to. Required scopes: `list_configuration:read`. # List all lists Source: https://docs.attio.com/rest-api/endpoint-reference/lists/list-all-lists https://api.attio.com/openapi/api get /v2/lists List all lists that your access token has access to. lists are returned in the order that they are sorted in the sidebar. Required scopes: `list_configuration:read`. # Update a list Source: https://docs.attio.com/rest-api/endpoint-reference/lists/update-a-list https://api.attio.com/openapi/api patch /v2/lists/{list} Updates an existing list. Permissions for the list are controlled with the `workspace_access` and `workspace_member_access` parameters. Please note that lists must have either `workspace_access` set to `"full-access"` or one or more element of `workspace_member_access` with a `"full-access"` level. It is also possible to receive a `403` billing error if your workspace is not on a plan that supports either advanced workspace or workspace member level access for lists. Changing the parent object of a list is not possible through the API as it can have unintended side-effects that should be considered carefully. If you wish to carry out a parent object change you should do so through the UI. Required scopes: `list_configuration:read-write`. # Get a meeting Source: https://docs.attio.com/rest-api/endpoint-reference/meetings/get-a-meeting https://api.attio.com/openapi/api get /v2/meetings/{meeting_id} Get a single meeting by ID. This endpoint is in beta. We will aim to avoid breaking changes, but small updates may be made as we roll out to more users. Required scopes: `meeting:read`, `record_permission:read`. # List meetings Source: https://docs.attio.com/rest-api/endpoint-reference/meetings/list-meetings https://api.attio.com/openapi/api get /v2/meetings Lists all meetings in the workspace using a deterministic sort order. This endpoint is in beta. We will aim to avoid breaking changes, but small updates may be made as we roll out to more users. Required scopes: `meeting:read`, `record_permission:read`. # Identify Source: https://docs.attio.com/rest-api/endpoint-reference/meta/identify https://api.attio.com/openapi/api get /v2/self Identify the current access token, the workspace it is linked to, and any permissions it has. # Create a note Source: https://docs.attio.com/rest-api/endpoint-reference/notes/create-a-note https://api.attio.com/openapi/api post /v2/notes Creates a new note for a given record. Required scopes: `note:read-write`, `object_configuration:read`, `record_permission:read`. # Delete a note Source: https://docs.attio.com/rest-api/endpoint-reference/notes/delete-a-note https://api.attio.com/openapi/api delete /v2/notes/{note_id} Delete a single note by ID. Required scopes: `note:read-write`. # Get a note Source: https://docs.attio.com/rest-api/endpoint-reference/notes/get-a-note https://api.attio.com/openapi/api get /v2/notes/{note_id} Get a single note by ID. Required scopes: `note:read`, `object_configuration:read`, `record_permission:read`. # List notes Source: https://docs.attio.com/rest-api/endpoint-reference/notes/list-notes https://api.attio.com/openapi/api get /v2/notes List notes for all records or for a specific record. Required scopes: `note:read`, `object_configuration:read`, `record_permission:read`. # Create an object Source: https://docs.attio.com/rest-api/endpoint-reference/objects/create-an-object https://api.attio.com/openapi/api post /v2/objects Creates a new custom object in your workspace. Required scopes: `object_configuration:read-write`. # Get an object Source: https://docs.attio.com/rest-api/endpoint-reference/objects/get-an-object https://api.attio.com/openapi/api get /v2/objects/{object} Gets a single object by its `object_id` or slug. Required scopes: `object_configuration:read`. # List objects Source: https://docs.attio.com/rest-api/endpoint-reference/objects/list-objects https://api.attio.com/openapi/api get /v2/objects Lists all system-defined and user-defined objects in your workspace. Required scopes: `object_configuration:read`. # Update an object Source: https://docs.attio.com/rest-api/endpoint-reference/objects/update-an-object https://api.attio.com/openapi/api patch /v2/objects/{object} Updates a single object. The object to be updated is identified by its `object_id`. Required scopes: `object_configuration:read-write`. # OpenAPI Source: https://docs.attio.com/rest-api/endpoint-reference/openapi Access the OpenAPI specification for the Attio REST API Attio exposes a public OpenAPI specification for the Attio REST API. The specification is available [here](https://api.attio.com/openapi/api). # Assert a person Record Source: https://docs.attio.com/rest-api/endpoint-reference/people/assert-a-person-record https://api.attio.com/openapi/standard-objects put /v2/objects/people/records Use this endpoint to create or update person records, using a unique attribute to search for existing People (for example the `email_addresses` attribute). If a person is found with the same value for the matching attribute, that person will be updated. If no person with the same value for the matching attribute is found, a new person will be created instead. If you would like to avoid matching, please use the Create person endpoint. If the matching attribute is a multiselect attribute, new values will be added and existing values will not be deleted. For any other multiselect attribute, all values will be either created or deleted as necessary to match the list of supplied values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a person Record Source: https://docs.attio.com/rest-api/endpoint-reference/people/create-a-person-record https://api.attio.com/openapi/standard-objects post /v2/objects/people/records Creates a new person Record. This endpoint will throw on conflicts of unique attributes, like `email_addresses`. If you would prefer to update person records on conflicts, please use the Assert person record endpoint instead. Please note, the `avatar_url` attribute cannot currently be set via the API. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Delete a person Record Source: https://docs.attio.com/rest-api/endpoint-reference/people/delete-a-person-record https://api.attio.com/openapi/standard-objects delete /v2/objects/people/records/{record_id} Deletes a single person record by ID. Required scopes: `object_configuration:read`, `record_permission:read-write`. # Get a person Record Source: https://docs.attio.com/rest-api/endpoint-reference/people/get-a-person-record https://api.attio.com/openapi/standard-objects get /v2/objects/people/records/{record_id} Gets a single person record by its `record_id`. Required scopes: `record_permission:read`, `object_configuration:read`. # List person record attribute values Source: https://docs.attio.com/rest-api/endpoint-reference/people/list-person-record-attribute-values https://api.attio.com/openapi/standard-objects get /v2/objects/people/records/{record_id}/attributes/{attribute}/values Gets all values for a given attribute on a person record. Historic values can be queried using the `show_historic` query param. Historic values cannot be queried on COMINT (Communication Intelligence) or enriched attributes and the endpoint will return a 400 error if this is attempted. Historic values are sorted from oldest to newest (by `active_from`). Some attributes are subject to billing status and will return an empty array of values if theworkspace being queried does not have the required billing flag enabled. Required scopes: `record_permission:read`, `object_configuration:read`. # List person record entries Source: https://docs.attio.com/rest-api/endpoint-reference/people/list-person-record-entries https://api.attio.com/openapi/standard-objects get /v2/objects/people/records/{record_id}/entries List all entries, across all lists, for which this person record is the parent. Required scopes: `record_permission:read`, `object_configuration:read`, `list_entry:read`. # List person records Source: https://docs.attio.com/rest-api/endpoint-reference/people/list-person-records https://api.attio.com/openapi/standard-objects post /v2/objects/people/records/query Lists person records, with the option to filter and sort results. Required scopes: `record_permission:read`, `object_configuration:read`. # Update a person Record Source: https://docs.attio.com/rest-api/endpoint-reference/people/update-a-person-record https://api.attio.com/openapi/standard-objects patch /v2/objects/people/records/{record_id} Use this endpoint to update person records by `record_id`. If the update payload includes multiselect attributes, the values supplied will be created and prepended to the list of values that already exist (if any). Use the [Assert person endpoint](/reference/put_v2-objects-people-records) to overwrite or remove multiselect attribute values. Please note, the `avatar_url` attribute cannot currently be updated via the API. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Assert a record Source: https://docs.attio.com/rest-api/endpoint-reference/records/assert-a-record https://api.attio.com/openapi/api put /v2/objects/{object}/records Use this endpoint to create or update people, companies and other records. A matching attribute is used to search for existing records. If a record is found with the same value for the matching attribute, that record will be updated. If no record with the same value for the matching attribute is found, a new record will be created instead. If you would like to avoid matching, please use the [Create record endpoint](/rest-api/endpoint-reference/records/create-a-record). If the matching attribute is a multiselect attribute, new values will be added and existing values will not be deleted. For any other multiselect attribute, all values will be either created or deleted as necessary to match the list of supplied values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a record Source: https://docs.attio.com/rest-api/endpoint-reference/records/create-a-record https://api.attio.com/openapi/api post /v2/objects/{object}/records Creates a new person, company or other record. This endpoint will throw on conflicts of unique attributes. If you would prefer to update records on conflicts, please use the [Assert record endpoint](/rest-api/endpoint-reference/records/assert-a-record) instead. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Delete a record Source: https://docs.attio.com/rest-api/endpoint-reference/records/delete-a-record https://api.attio.com/openapi/api delete /v2/objects/{object}/records/{record_id} Deletes a single record (e.g. a company or person) by ID. Required scopes: `object_configuration:read`, `record_permission:read-write`. # Get a record Source: https://docs.attio.com/rest-api/endpoint-reference/records/get-a-record https://api.attio.com/openapi/api get /v2/objects/{object}/records/{record_id} Gets a single person, company or other record by its `record_id`. Required scopes: `record_permission:read`, `object_configuration:read`. # List record attribute values Source: https://docs.attio.com/rest-api/endpoint-reference/records/list-record-attribute-values https://api.attio.com/openapi/api get /v2/objects/{object}/records/{record_id}/attributes/{attribute}/values Gets all values for a given attribute on a record. Historic values can be queried using the `show_historic` query param. Historic values cannot be queried on COMINT (Communication Intelligence) or enriched attributes and the endpoint will return a 400 error if this is attempted. Historic values are sorted from oldest to newest (by `active_from`). Some attributes are subject to billing status and will return an empty array of values if theworkspace being queried does not have the required billing flag enabled. Required scopes: `record_permission:read`, `object_configuration:read`. # List record entries Source: https://docs.attio.com/rest-api/endpoint-reference/records/list-record-entries https://api.attio.com/openapi/api get /v2/objects/{object}/records/{record_id}/entries List all entries, across all lists, for which this record is the parent. Required scopes: `record_permission:read`, `object_configuration:read`, `list_entry:read`. # List records Source: https://docs.attio.com/rest-api/endpoint-reference/records/list-records https://api.attio.com/openapi/api post /v2/objects/{object}/records/query Lists people, company or other records, with the option to filter and sort results. Required scopes: `record_permission:read`, `object_configuration:read`. # Search records Source: https://docs.attio.com/rest-api/endpoint-reference/records/search-records https://api.attio.com/openapi/api post /v2/objects/records/search The search records endpoint provides a convenient way to fuzzy search for records across one or more objects. The matching strategy employed in this endpoint follows the in-product strategy and will match names, domains, emails, phone numbers and social handles on people and companies, and labels on all other objects. Please note, results returned from this endpoint are eventually consistent. For results which are guaranteed to be up to date, please use the record query endpoint instead. This endpoint is in alpha and may be subject to breaking changes as we gather feedback. Required scopes: `record_permission:read`, `object_configuration:read`. # Update a record (append multiselect values) Source: https://docs.attio.com/rest-api/endpoint-reference/records/update-a-record-append-multiselect-values https://api.attio.com/openapi/api patch /v2/objects/{object}/records/{record_id} Use this endpoint to update people, companies, and other records by `record_id`. If the update payload includes multiselect attributes, the values supplied will be created and prepended to the list of values that already exist (if any). Use the `PUT` endpoint to overwrite or remove multiselect attribute values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Update a record (overwrite multiselect values) Source: https://docs.attio.com/rest-api/endpoint-reference/records/update-a-record-overwrite-multiselect-values https://api.attio.com/openapi/api put /v2/objects/{object}/records/{record_id} Use this endpoint to update people, companies, and other records by `record_id`. If the update payload includes multiselect attributes, the values supplied will overwrite/remove the list of values that already exist (if any). Use the `PATCH` endpoint to append multiselect values without removing those that already exist. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a task Source: https://docs.attio.com/rest-api/endpoint-reference/tasks/create-a-task https://api.attio.com/openapi/api post /v2/tasks Creates a new task. At present, tasks can only be created from plaintext without record reference formatting. Required scopes: `task:read-write`, `object_configuration:read`, `record_permission:read`, `user_management:read`. # Delete a task Source: https://docs.attio.com/rest-api/endpoint-reference/tasks/delete-a-task https://api.attio.com/openapi/api delete /v2/tasks/{task_id} Delete a task by ID. Required scopes: `task:read-write`. # Get a task Source: https://docs.attio.com/rest-api/endpoint-reference/tasks/get-a-task https://api.attio.com/openapi/api get /v2/tasks/{task_id} Get a single task by ID. Required scopes: `task:read`, `object_configuration:read`, `record_permission:read`, `user_management:read`. # List tasks Source: https://docs.attio.com/rest-api/endpoint-reference/tasks/list-tasks https://api.attio.com/openapi/api get /v2/tasks List all tasks. Results are sorted by creation date, from oldest to newest. Required scopes: `task:read`, `object_configuration:read`, `record_permission:read`, `user_management:read`. # Update a task Source: https://docs.attio.com/rest-api/endpoint-reference/tasks/update-a-task https://api.attio.com/openapi/api patch /v2/tasks/{task_id} Updates an existing task by `task_id`. At present, only the `deadline_at`, `is_completed`, `linked_records`, and `assignees` fields can be updated. Required scopes: `task:read-write`, `object_configuration:read`, `record_permission:read`, `user_management:read`. # Get a thread Source: https://docs.attio.com/rest-api/endpoint-reference/threads/get-a-thread https://api.attio.com/openapi/api get /v2/threads/{thread_id} Get all comments in a thread. To view threads on records, you will need the `object_configuration:read` and `record_permission:read` scopes. To view threads on list entries, you will need the `list_configuration:read` and `list_entry:read` scopes. Required scopes: `comment:read`. # List threads Source: https://docs.attio.com/rest-api/endpoint-reference/threads/list-threads https://api.attio.com/openapi/api get /v2/threads List threads of comments on a record or list entry. To view threads on records, you will need the `object_configuration:read` and `record_permission:read` scopes. To view threads on list entries, you will need the `list_configuration:read` and `list_entry:read` scopes. Required scopes: `comment:read`. # Get call transcript Source: https://docs.attio.com/rest-api/endpoint-reference/transcripts/get-call-transcript https://api.attio.com/openapi/api get /v2/meetings/{meeting_id}/call_recordings/{call_recording_id}/transcript Get the transcript for a call recording. This endpoint is in beta. We will aim to avoid breaking changes, but small updates may be made as we roll out to more users. Required scopes: `meeting:read`, `call_recording:read`. # Assert a user record Source: https://docs.attio.com/rest-api/endpoint-reference/users/assert-a-user-record https://api.attio.com/openapi/standard-objects put /v2/objects/users/records Use this endpoint to create or update user records, using a unique attribute to search for existing users (for example the `primary_email_address` attribute). If a user is found with the same value for the matching attribute, that user will be updated, otherwise a new user will be created instead. If the matching attribute is a multiselect attribute, new values will be added and existing values will not be deleted. For any other multiselect attribute, all values will be either created or deleted as necessary to match the list of supplied values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a user record Source: https://docs.attio.com/rest-api/endpoint-reference/users/create-a-user-record https://api.attio.com/openapi/standard-objects post /v2/objects/users/records Creates a new user record. This endpoint will throw on conflicts of unique attributes, like `primary_email_address`. If you would prefer to update user records on conflicts, please use the Assert user record endpoint instead. Please note, the `avatar_url` attribute cannot currently be set via the API. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Delete a user record Source: https://docs.attio.com/rest-api/endpoint-reference/users/delete-a-user-record https://api.attio.com/openapi/standard-objects delete /v2/objects/users/records/{record_id} Deletes a single user record by ID. Required scopes: `object_configuration:read`, `record_permission:read-write`. # Get a user record Source: https://docs.attio.com/rest-api/endpoint-reference/users/get-a-user-record https://api.attio.com/openapi/standard-objects get /v2/objects/users/records/{record_id} Gets a single user record by its `record_id`. Required scopes: `record_permission:read`, `object_configuration:read`. # List user record attribute values Source: https://docs.attio.com/rest-api/endpoint-reference/users/list-user-record-attribute-values https://api.attio.com/openapi/standard-objects get /v2/objects/users/records/{record_id}/attributes/{attribute}/values Gets all values for a given attribute on a user record. Historic values can be queried using the `show_historic` query param. Historic values are sorted from oldest to newest (by `active_from`). Required scopes: `record_permission:read`, `object_configuration:read`. # List user record entries Source: https://docs.attio.com/rest-api/endpoint-reference/users/list-user-record-entries https://api.attio.com/openapi/standard-objects get /v2/objects/users/records/{record_id}/entries List all entries, across all lists, for which this user record is the parent. Required scopes: `record_permission:read`, `object_configuration:read`, `list_entry:read`. # List user records Source: https://docs.attio.com/rest-api/endpoint-reference/users/list-user-records https://api.attio.com/openapi/standard-objects post /v2/objects/users/records/query Lists user records, with the option to filter and sort results. Required scopes: `record_permission:read`, `object_configuration:read`. # Update a user Record Source: https://docs.attio.com/rest-api/endpoint-reference/users/update-a-user-record https://api.attio.com/openapi/standard-objects patch /v2/objects/users/records/{record_id} Use this endpoint to update user records by `record_id`. If the update payload includes multiselect attributes, the values supplied will be created and prepended to the list of values that already exist (if any). Use the [Assert user endpoint](/reference/put_v2-objects-users-records) to overwrite or remove multiselect attribute values. Please note, the `avatar_url` attribute cannot currently be updated via the API. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a webhook Source: https://docs.attio.com/rest-api/endpoint-reference/webhooks/create-a-webhook https://api.attio.com/openapi/api post /v2/webhooks Create a webhook and associated subscriptions. Required scopes: `webhook:read-write`. # Delete a webhook Source: https://docs.attio.com/rest-api/endpoint-reference/webhooks/delete-a-webhook https://api.attio.com/openapi/api delete /v2/webhooks/{webhook_id} Delete a webhook by ID. Required scopes: `webhook:read-write`. # Get a webhook Source: https://docs.attio.com/rest-api/endpoint-reference/webhooks/get-a-webhook https://api.attio.com/openapi/api get /v2/webhooks/{webhook_id} Get a single webhook. Required scopes: `webhook:read`. # List webhooks Source: https://docs.attio.com/rest-api/endpoint-reference/webhooks/list-webhooks https://api.attio.com/openapi/api get /v2/webhooks Get all of the webhooks in your workspace. Required scopes: `webhook:read`. # Update a webhook Source: https://docs.attio.com/rest-api/endpoint-reference/webhooks/update-a-webhook https://api.attio.com/openapi/api patch /v2/webhooks/{webhook_id} Update a webhook and associated subscriptions. Required scopes: `webhook:read-write`. # Get a workspace member Source: https://docs.attio.com/rest-api/endpoint-reference/workspace-members/get-a-workspace-member https://api.attio.com/openapi/api get /v2/workspace_members/{workspace_member_id} Gets a single workspace member by ID. Required scopes: `user_management:read`. # List workspace members Source: https://docs.attio.com/rest-api/endpoint-reference/workspace-members/list-workspace-members https://api.attio.com/openapi/api get /v2/workspace_members Lists all workspace members in the workspace. Required scopes: `user_management:read`. # Assert a workspace record Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/assert-a-workspace-record https://api.attio.com/openapi/standard-objects put /v2/objects/workspaces/records Use this endpoint to create or update workspace records, using a unique attribute to search for existing workspaces (for example the `workspace_id` attribute). If a workspace is found with the same value for the matching attribute, that workspace will be updated, otherwise a new workspace will be created instead. If the matching attribute is a multiselect attribute, new values will be added and existing values will not be deleted. For any other multiselect attribute, all values will be either created or deleted as necessary to match the list of supplied values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Create a workspace record Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/create-a-workspace-record https://api.attio.com/openapi/standard-objects post /v2/objects/workspaces/records Creates a new workspace record. This endpoint will throw on conflicts of unique attributes, like `workspace_id`. If you would prefer to update workspace records on conflicts, please use the Assert workspace record endpoint instead. Required scopes: `record_permission:read-write`, `object_configuration:read`. # Delete a workspace record Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/delete-a-workspace-record https://api.attio.com/openapi/standard-objects delete /v2/objects/workspaces/records/{record_id} Deletes a single workspace record by ID. Required scopes: `object_configuration:read`, `record_permission:read-write`. # Get a workspace record Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/get-a-workspace-record https://api.attio.com/openapi/standard-objects get /v2/objects/workspaces/records/{record_id} Gets a single workspace record by its `record_id`. Required scopes: `record_permission:read`, `object_configuration:read`. # List workspace record attribute values Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/list-workspace-record-attribute-values https://api.attio.com/openapi/standard-objects get /v2/objects/workspaces/records/{record_id}/attributes/{attribute}/values Gets all values for a given attribute on a workspace record. Historic values can be queried using the `show_historic` query param. Historic values are sorted from oldest to newest (by `active_from`). Required scopes: `record_permission:read`, `object_configuration:read`. # List workspace record entries Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/list-workspace-record-entries https://api.attio.com/openapi/standard-objects get /v2/objects/workspaces/records/{record_id}/entries List all entries, across all lists, for which this workspace record is the parent. Required scopes: `record_permission:read`, `object_configuration:read`, `list_entry:read`. # List workspace records Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/list-workspace-records https://api.attio.com/openapi/standard-objects post /v2/objects/workspaces/records/query Lists workspace records, with the option to filter and sort results. Required scopes: `record_permission:read`, `object_configuration:read`. # Update a workspace Record Source: https://docs.attio.com/rest-api/endpoint-reference/workspaces/update-a-workspace-record https://api.attio.com/openapi/standard-objects patch /v2/objects/workspaces/records/{record_id} Use this endpoint to update workspace records by `record_id`. If the update payload includes multiselect attributes, the values supplied will be created and prepended to the list of values that already exist (if any). Use the [Assert workspace endpoint](/rest-api/endpoint-reference/standard-objects/workspaces/assert-a-workspace-record) to overwrite or remove multiselect attribute values. Required scopes: `record_permission:read-write`, `object_configuration:read`. # How to authenticate requests Source: https://docs.attio.com/rest-api/how-to/authentication How to generate access tokens and make requests In order to make requests to the Attio REST API, you need to generate an access token. There are two ways to generate an access token: 1. By implementing an OAuth 2.0 flow 2. By generating an API key for your workspace You should prefer the OAuth 2.0 flow if building an app for multiple workspaces. If you are building an app for a single workspace, you can manually generate an API key to make requests on behalf of that workspace only. ## Generating access tokens ### OAuth 2.0 Attio implements the standard [OAuth 2.0 specification](https://datatracker.ietf.org/doc/html/rfc6749). You can find the reference for our OAuth authorize, token exchange and introspect endpoints [here](/rest-api/endpoint-reference/oauth-20/authorize-endpoint). If you would prefer a tutorial on how to implement an OAuth 2.0 flow into an existing app, you can find one [here](/rest-api/tutorials/connect-an-app-through-oauth). ### API key If you only need a token for a single workspace, you can generate an API key in the developer settings page of your apps. You can find docs on to do this [here](https://attio.com/help/apps/other-apps/generating-an-api-key). ## Using tokens Both OAuth access tokens and single-workspace access token are used in the same way. Pass the value of the token in the `Authorization` header of your requests like so. ``` Authorization: Bearer ``` We also support [HTTP Basic Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization#basic_authentication), where the username is the token and the password is left blank. However, we recommend using Bearer authentication where possible. ### Scopes Both OAuth access tokens and single-workspace access tokens use scopes to control the resources that the token has access to and the actions that can be performed on those resources. The possible scopes for OAuth and single-workspace access tokens are the same. The reference documentation for each endpoint includes a "Required scopes" section that lists the scopes needed to call that endpoint. When using an OAuth access token, the scopes are specified by configuring the scope settings for your app in the developer dashboard. When using a single-workspace access token, the scopes are specified in the settings UI when generating the token. Scopes for single-workspace access tokens can also be modified on existing tokens. # How to apply filters and sorts Source: https://docs.attio.com/rest-api/how-to/filtering-and-sorting Searching for just the records you need Some of our endpoints allow specifying `filter` or `sorts` objects as part of the request. These properties can help reduce the size of the result set or get them back in a more appropriate order. ## Filtering Attio supports two distinct formats for filtering. There is the verbose format, which supports a wider variety of operators and conditions, and a shorthand format, which is useful for quick equality checks. ### Shorthand filters Shorthand filters generally look like this: ```json People called "John Smith" with the email "john@smith.com" theme={"system"} POST /v2/objects/companies/records/query Content-Type: application/json { "filter": { "name": "John Smith", "email_addresses": "john@smith.com" } } ``` ### Verbose filters Verbose filters allow joining multiple different conditions together, or querying for different properties of the attribute value. All shorthand syntaxes can be expressed in the verbose syntax. For example, the above filter can also be written as: ```json theme={"system"} POST /v2/objects/companies/records/query Content-Type: application/json { "filter": { "$and": [ { "name": { "full_name": { "$eq": "John Smith" } } }, { "email_addresses": { "email_address": { "$eq": "john@smith.com" } } } ] } } ``` Note that we're using a logical operator (`$and`) to combine these two conditions, and that we're querying specific properties on the attributes (`full_name` and `normalized_email_address`). Each attribute type has specific properties available, and so the set of possible filters varies by attribute type, but every attribute type is filterable in some way. We have examples of filtering by each attribute type in our [attribute types documentation](/docs/attribute-types). Next, let's walk through some more advanced filtering, starting with the comparison operators. ## Comparison operators There are nine comparison operators in total. `$eq` is by far the most common, this operator checks for equality. It is supported by every attribute type. If you're using shorthand syntax, this is usually the implied operator, but it can also be specified explicitly: ```json Deals with an exact name theme={"system"} { "name": { "$eq": "Contract with Apple" } } ``` `$not_empty` is also available on some attribute types, this operator allows filtering results based on whether there is any value defined at all, for example: ```json Companies which have at least one domain theme={"system"} { "domains": { "$not_empty": true } } ``` `$in`can be used to check if the record or entry has a value that is part of a set. ```json Records where record_id is one of many values theme={"system"} { "filter": { "record_id": { "$in": ["000e8881-37cc-41d2-bc22-39fe35e76e6b", "592dc9d8-548b-4148-813f-1259055ca83c"] } } } ``` There are also operators for string properties and numeric/date properties: ### String comparisons For string-like properties or attributes, there are three further operators. `$contains` can be used for matching parts of a string, case-insensitively: ```json Companies in New York theme={"system"} { "primary_location": { "locality": { "$contains": "new york" } } } ``` ```json Companies with "LTD" in the name theme={"system"} { "name": { "$contains": "LTD" } } ``` `$starts_with` and `$ends_with` can match on the beginning or the end of the string, respectively: ```json People with phone numbers starting +44 theme={"system"} { "phone_numbers": { "$starts_with": "+44" } } ``` ```json People with a job title "X engineer" theme={"system"} { "job_title": { "$ends_with": "of things" } } ``` Note that these can be combined on the same property or attribute to achieve a logical AND: ```json Phone number starts with +44 and ends with 798 theme={"system"} { "phone_numbers": { "$starts_with": "+44", "$ends_with": "798" } } ``` ### Numeric or date comparisons There are four operators for comparing sortable properties like numbers or dates: 1. **Less than** (`$lt`), finds records where the value is strictly less than (exclusive) the given value 2. **Less than or equal** (`$lte`), finds records where the value is either less than or the same as the given value 3. **Greater than or equal** (`$gte`), finds records where the value is either greater than or the same as the given value 4. **Greater than** (`$gt`), finds records where the value is strictly more than (exclusive) the given value ```json People with 1000 or more Twitter followers theme={"system"} { "twitter_follower_count": { "$gte": 1000 } } ``` ```json People with between 100 and 200 followers theme={"system"} { "twitter_follower_count": { "$gte": 100, "$lt": 200 } } ``` You can also combine multiple comparators to find values between two points: ```json Companies founded in 2019 theme={"system"} { "foundation_date": { "$gte": "2019-01-01", "$lte": "2019-12-31" } } ``` ## Logical operators You can combine multiple conditions using the `$and`, `$or` and `$not` operators. ### `$and` operator `$and` specifies that all conditions must match. If using the shorthand syntax with multiple attributes, this operator is implied. Note that you can also use the shorthand syntax for individual conditions—see the following example. ```json Deals assigned to Lauren in the "In Progress" state theme={"system"} { "$and": [ {"stage": "In Progress"}, { "owner": { "referenced_actor_type": "workspace-member", "referenced_actor_id": "[laurens-id]" } } ] } ``` ### `$or` operator `$or` specifies that at least one of the conditions must match. It is not an exclusive-or, if all conditions match it will still pass. ```json List entries on a kanban board in either the "One" or "Two" stage theme={"system"} { "$or": [{"stage": "One"}, {"stage": "Two"}] } ``` ### `$not` operator Attio doesn't offer negative operators, for example there is no inverse of `$eq` like `$neq`. Instead, filters should be wrapped using the `$not` operator, which matches all documents which don't meet the condition. ```json People not called John theme={"system"} { "$not": { "name": { "first_name": "John" } } } ``` ```json Deals not in the "In Progress" state theme={"system"} { "$not": { "stage": "In Progress" } } ``` ### Combining logical operators It's possible to combine logical operators to build up trees of filters. For example, you could express multiple `$and` conditions, where some of them are a `$not`: ```json Companies with Apple in their name that aren't using an apple domain theme={"system"} { "$and": [ {"name": {"$contains": "Apple"}}, { "$not": { "domains": { "root_domain": "apple.com" } } } ] } ``` Or you could query for "deals that are owned by Alice or Bob that are worth more than \$500: ```json Deals owned by Alice/Bob worth more than $500 theme={"system"} { "$and": [ { "$or": [ { "owner": { "referenced_actor_type": "workspace-member", "referenced_actor_id": "[alices-id]" } }, { "owner": { "referenced_actor_type": "workspace-member", "referenced_actor_id": "[bobs-id]" } } ] }, { "value": { "$gt": 500 } } ] } ``` ## Paths and parents For [record reference attributes](/docs/attribute-types/attribute-types-record-reference), it's possible to use special `path` filtering by drilling down into the target objects. This filtering method is also supported on list entries. For example, let's assume we have a list of people we want to hire, called "Candidates" (the `api_slug` is `candidates`). We could then write a query to find entries where the person has an `@apple.com` email address: ```json List entries filtered by their parent record email theme={"system"} { "path": [ ["candidates", "parent_record"], ["people", "email_addresses"] ], "constraints": { "email_domain": "apple.com" } } ``` Note that we're using a special attribute called `parent_record` that we can use for filtering any list entry. We can even use these drill-down queries to express a more complicated query, like "entries where the candidate works at the same company as Steve Jobs": ```json Candidates who have worked with Steve Jobs theme={"system"} { "path": [ ["candidates", "parent_record"], ["people", "company"], ["company", "team"] ], "constraints": { "target_object": "people", "target_record_id": "[steve-jobs-record-id]" } } ``` ## Sorting Sorting allows us to get our results back in a particular order, based on attribute values. Each sort must specify a `direction`. If the target attribute is composed of multiple properties (like [(Personal) name](/docs/attribute-types/attribute-types-personal-name)), `field` can also be specified. We can do sorting by `attribute`, which is either a slug or ID. For example, we could sort People by their last name, then their email address: ```json People sorted by last name, then email theme={"system"} { "sorts": [ {"direction": "asc", "attribute": "name", "field": "last_name"}, {"direction": "desc", "attribute": "email_addresses"} ] } ``` We can also sort using paths, which works similarly to filtering by path. Instead of specifying `attribute`, you specify a `path` property which resolves to the attribute of the related record(s): ```json People sorted by their Company name theme={"system"} { "sorts": [ { "direction": "asc", "path": [ ["people", "company"], ["companies", "name"] ] } ] } ``` # How to paginate API results Source: https://docs.attio.com/rest-api/how-to/pagination Retrieving particular ranges of data API endpoints which are expected to return large numbers of results will use pagination to return a limited number of items at a time. Depending on the endpoint, pagination will be implemented through either limit/offset pagination, or cursor-based pagination. ## Limit/offset pagination When using limit/offset pagination, two parameters are used to provide pagination functionality: * `limit` controls the maximum number of results that an endpoint can return. The default value for limit is documented on each specific endpoint. * `offset` controls how many values to skip over in the result set. By default, it is always 0. When querying all results, your initial call should pass an `offset` value of 0. If the number of results you receive is less than the value of the `limit` parameter (or the default limit if none was passed explicitly), you have reached the end of the result set and can end pagination. Otherwise, make another API call with a new `offset` value set to the previous `offset` + `limit` to get the next page, and then repeat until you are at the end of the list. For example, if there were 122 records available, your queries would look something like this for a `GET` endpoint using query parameters. ```http theme={"system"} GET /v2/notes?limit=50 # Results 1 to 50 GET /v2/notes?limit=50&offset=50 # Results 51 to 100 GET /v2/notes?limit=50&offset=100 # Results 101 to 122, less than limit, stop here ``` For a `POST` endpoint using a body, your requests would look like this. ```http theme={"system"} POST /v2/objects/people/records/query { "limit": 50, "offset": 50 } ``` ## Cursor-based pagination Cursor-based pagination is implemented through the `limit` and `cursor` parameters. You will also receive a `next_cursor` value in the API response. * `cursor` should only be set to the opaque cursor value provided in the API response and will be used to get the next page of results. * `limit` is the same as in limit/offset pagination; it controls the maximum number of results that an endpoint can return. Your initial request should omit the `cursor` parameter and specify a `limit` value (or rely on the endpoint's default). Your response will include `pagination.next_cursor` which you should use in your next request by passing it as the `cursor` parameter. It is important to keep the limit as well as any filter parameters consistent between requests to avoid receiving unexpected results. For example, to call our list meetings endpoint, you would do the following: ```http theme={"system"} GET /v2/meetings?limit=50 GET /v2/meetings?limit=50&cursor=cursor-1 GET /v2/meetings?limit=50&cursor=cursor-2 ``` ##### Example response ```json theme={"system"} { "data": [/* meeting results here */], "pagination": { "next_cursor": "opaque-cursor-value-here" } } ``` # How to handle rate limits Source: https://docs.attio.com/rest-api/how-to/rate-limiting How to ensure your app handles rate limits gracefully The Attio API applies rate limits to all API calls to ensure fair usage and maintain the availability and stability of the platform. Our rate limit across the whole API is **100 requests per second** for read requests, **25 requests per second** for write requests. We may occasionally reduce the rate limit as part of incident response to protect our other systems, and we may also permanently lower it for specific APIs which handle a lot of data (this will be documented on the endpoint if so). This means that your software should be prepared to receive this response, and handle it appropriately, even if you don’t currently anticipate making this many requests. ## Rate limit response If you exceed the limit, you'll get a special HTTP response, like this: ```http HTTP theme={"system"} HTTP/1.1 429 Too Many Requests Retry-After: Tue, 23 May 2023 14:42:01 GMT Content-Type: application/json { "status_code": 429, "type": "rate_limit_error", "code": "rate_limit_exceeded", "message": "Rate limit exceeded, please try again later" } ``` Rate limit responses always have the HTTP status code `429`. They also always include a `Retry-After` header, which is a date at which the limit resets (usually the following second), and they may also include additional debugging information in the JSON body. ### Handling rate limit responses A rate limited response means that we have not processed the request, so it can be safely retried after the limit has reset. Typically this will be in the next clock second. Most programming languages offer a sleep command or equivalent that allows waiting for the reset time to elapse. Alternatively, you might want to put the request into a background queue to be processed in a different execution thread later. # How to configure webhooks Source: https://docs.attio.com/rest-api/how-to/webhooks Responding to changes in real-time Webhooks allow you to subscribe to changes that happen in Attio and then receive real-time HTTP requests to a chosen target URL to notify you of these changes. This pattern can be useful in a wide range of contexts, but is often implemented by those who want to build real-time data syncs (e.g. an ETL pipeline) or fire automations in a timely manner (e.g. Attio’s own Zapier integration is powered by webhooks). ## Creating webhooks There are two places you can create webhooks: in our settings pages, and the API. ### Creating using the API We offer a range of endpoints for creating, updating, deleting and viewing webhooks. You can find these endpoints in the [webhooks API reference](/rest-api/endpoint-reference/webhooks). Creating webhooks over the API is essential for those building integrations for Attio that will operate for many customers. The webhook APIs also allow you to utilise our powerful filtering functionality (see “Filtering” section below). ### Creating using settings page You can create webhooks for an integration in the developer settings page. Please note that webhooks created with tokens that were created through our OAuth sign up flow will not be shown in the developer settings page. ## Authenticating When receiving webhooks, you should ensure that the request came from us. We cryptographically sign every webhook request using your webhook secret, and include it as HTTP header called `Attio-Signature` (this is duplicated as `X-Attio-Signature` to support legacy middleware). The `Attio-Signature` value is calculated using a SHA256 HMAC of the request body using your webhook secret as the secret. The webhook's secret is viewable inside the developer settings page and in the API response when creating the webhook. To verify that webhooks came from us, you should also construct the signature on your side using the same algorithm, then verify that it matches the one in the request. We encode the Attio-Signature as a hexadecimal string, and we only sign the request body, which we interpret as a UTF-8 string. Here's an example in NodeJS for verifying the webhook signature: ```typescript TypeScript theme={"system"} const webhookBody = request.body const webhookSignature = request.headers["attio-signature"] // Generate signature ourselves const webhookSecret = "..." const hmac = crypto.createHmac("sha256", webhookSecret) hmac.update(webhookBody) const expectedSignature = hmac.digest("hex") // Compare signature if (!crypto.timingSafeEqual(webhookSignature, expectedSignature)) { throw new Error("Invalid signature") } ``` ## HTTPS Webhooks must target URLs secured with HTTPS. This is because targeting URLs using HTTP reveals the confidential content of webhooks to the public internet. In addition to exposing your data to 'man in the middle' attacks, webhooks delivered via HTTP can be read at any point in the journey to your server, for example, by cloud providers or logging services. Ensuring your target URL is encrypted with HTTPS keeps your data secure. ## Idempotency Webhooks guarantee at-least-once message delivery. Occasionally, due to network instability, Attio may send duplicate messages. To help deduplicate messages, Attio includes an `Idempotency-Key` header which will be different for each message, but the same between retries and redeliveries. ## Delivery attempts If you're receiving many duplicate messages, it may mean that you're not acknowledging them properly. Attio will mark a delivery as successful if the response code is within the 200-299 range (for example `200` or `202`).If you answer with any other code, Attio will retry delivery of the message up to 10 times with an exponential back-off, which will happen over approximately 3 days in total; after which, the webhook will be marked as degraded and we'll send you an email. Attio also enforces a 5 second timeout on requests to your target URL. Failure to respond within 5 seconds will be treated as a delivery failure. ## IP addresses We recommend using the request signature to validate the request instead of relying on IP allowlisting. This will mean that your integration does not require maintenance if we add new IP addresses. Attio delivers webhooks from a fixed set of IP addresses. In some environments with restrictive firewalls it might be necessary to allowlist these IPs, and from time to time we might need to add a new IP Address to our list. We'll endeavour to provide you with as much notice as possible before we change these. ```text Attio webhooks egress IP addresses theme={"system"} 34.76.181.69 35.189.212.204 35.190.200.137 104.199.25.43 35.205.134.181 34.77.170.251 104.155.38.31 35.240.20.227 35.205.218.25 34.77.63.171 35.195.180.236 104.199.20.44 34.78.73.25 34.77.104.7 35.205.250.54 34.78.179.95 35.189.210.201 34.77.106.144 104.155.115.39 34.78.11.169 35.241.187.180 35.240.124.129 35.241.222.75 35.195.62.68 ``` ## Delivery rate limiting To avoid overwhelming your server with a large burst of requests, Attio smoothes out webhook delivery with a rate limiter. Rate limiting is implemented on a per-target URL basis. We restrict delivery per URL to a maximum of 25 requests per second. Please contact support if you would like this number adjusted for your workspace. ## Testing webhooks The developer settings page provides the ability to deliver test payloads to your webhook's target URL. When building an integration that uses webhooks, this lets you quickly test that your integration is functioning, without having to modify real data in your workspace. To send a test payload: 1. Navigate to an integration the developer settings page and select an integration. 2. Open an existing webhook or create a new one inside your integration. 3. Ensure your webhook is subscribed to the events that you want to test. 4. Open the dropdown next to the event you want to send a test payload for and select "Send test event to target URL". 5. We'll make an HTTP request to your target URL. We populate test payloads with real data from your workspace. For example, when testing the `note.created` event, we'll set the `note_id` property on the payload to correspond to a real note you have created. In cases where this is not possible, for example if you have no notes in your system, we'll fallback to randomly generated fake data. Please note that filters are not taken into account when generating test data. ## Filtering To reduce the amount of webhooks you receive and help avoid writing client-side filtering code, it's possible to define rules to further limit the events Attio will send. Filters work by taking the payload of the generated webhook event, and running it against a set of rules that you define. For example, you might only care about updates to a particular attribute on a particular list, or about new notes on people but not companies. Our API will validate that the filter syntax you have provided is valid. Filters are currently only editable and viewable over the API. ### Filter syntax The filter syntax can be broken down into the following components. #### Logical joins ($and, $or) * An `$and` filter passes when all operations match the payload. * An `$or` filter passes when at least one operation matches the payload. #### Operations * `field`: Specifies which property of the webhook payload to apply the filter condition on. It supports nested properties using dot notation, such as `"actor.type"` and `"actor.id"`. * `operator`: The operator property defines the comparison operation to be used in the filter operation. The currently supported operators are: `"equals"` and `"not_equals"` * `value`: The value property specifies the value to compare against the chosen payload field using the operator. ### Filter examples **Subscribe to changes on the "Sales" list or the "Hiring" list** ```json JSON theme={"system"} { "$or": [ { "field": "id.list_id", "operator": "equals", "value": "2a33abd4-dae7-49d0-b6ed-b09da0d8f00b" // <-- Sales List ID }, { "field": "id.list_id", "operator": "equals", "value": "9d74e5c9-41eb-4d5c-b70b-d346ef15e13e" // <-- Hiring List ID } ] } ``` **Subscribe to changes to the value of the “Status” attribute of the Sales list** ```json JSON theme={"system"} { "$and": [ { "field": "id.list_id", "operator": "equals", "value": "2a33abd4-dae7-49d0-b6ed-b09da0d8f00b" // <-- Sales List ID }, { "field": "id.attribute_id", "operator": "equals", "value": "c65a3828-b5e9-46d9-afe6-c8319ae46412" // <-- Status Attribute ID } ] } ``` **Subscribe to changes made by workspace members** ```json JSON theme={"system"} { "$and": [ { "field": "actor.type", "operator": "equals", "value": "workspace-member" } ] } ``` **Subscribe to all events** ```json JSON theme={"system"} {"filter": null} ``` ## Migrating from V1 webhooks Webhooks were supported over the V1 API and have now been replaced by updated V2 Webhooks. Using V2 webhooks will allow you to use our new filtering system and receive payloads which are consistent with the rest of the V2 API (e.g. we now refer to “lists” instead of “collections”). V1 Webhook endpoints and even types will eventually be removed. Therefore, we recommend upgrading to use V2 Webhooks at your soonest convenience. ### Event Types The following V1 Webhook events should be considered deprecated: ``` entry.created entry-attribute.updated entry.deleted ``` These have been replaced by the following V2 event types which fire under exactly the same circumstances. ``` entry.created → list-entry.created entry-attribute.updated → list-entry.updated entry.deleted → list-entry.deleted ``` ### Payloads Your code will also need to take into account the changes in the payloads of the above events. Below are examples of payloads with V1 events and V2. #### entry.created ```json theme={"system"} // V1 { "event_type": "entry.created", "collection_id": "69815e80-949c-44c9-92be-242457a4be28", "entry_id": "861c1071-54ba-4d3d-b642-f72f7bcc8c7e" } // V2 { "event_type": "list-entry.created", "id": { "workspace_id": "928e88d9-de10-4e1c-9aef-36b07cb4260d", // New "list_id": "69815e80-949c-44c9-92be-242457a4be28", // Previously, collection_id "entry_id": "861c1071-54ba-4d3d-b642-f72f7bcc8c7e", // Previously, entry_id }, "parent_object_id": "7298c9b4-63ac-4b7e-8a74-4468d2e403a9", // New "parent_record_id": "6003a6aa-7122-45f1-b840-efe9231dfd06", // New } ``` #### entry-attribute.updated ```json theme={"system"} // V1 { "event_type": "entry-attribute.updated", "collection_id": "69815e80-949c-44c9-92be-242457a4be28", "entry_id": "861c1071-54ba-4d3d-b642-f72f7bcc8c7e", "attribute_id": "18b7bb8c-fc41-4b70-be0b-0dea00b3ca23" } // V2 { "event_type": "list-entry.updated", "id": { "workspace_id": "928e88d9-de10-4e1c-9aef-36b07cb4260d", // New "list_id": "69815e80-949c-44c9-92be-242457a4be28", // Previously, collection_id "entry_id": "861c1071-54ba-4d3d-b642-f72f7bcc8c7e", // Previously, entry_id "attribute_id": "18b7bb8c-fc41-4b70-be0b-0dea00b3ca23", // Previously, attribute_id }, "parent_object_id": "7298c9b4-63ac-4b7e-8a74-4468d2e403a9", // New "parent_record_id": "6003a6aa-7122-45f1-b840-efe9231dfd06", // New } ``` #### entry.deleted ```json theme={"system"} // V1 { "event_type": "entry.deleted", "collection_id": "69815e80-949c-44c9-92be-242457a4be28", "entry_id": "861c1071-54ba-4d3d-b642-f72f7bcc8c7e" } // V2 { "event_type": "list-entry.deleted", "id": { "workspace_id": "928e88d9-de10-4e1c-9aef-36b07cb4260d", // New "list_id": "69815e80-949c-44c9-92be-242457a4be28", // Previously, collection_id "entry_id": "861c1071-54ba-4d3d-b642-f72f7bcc8c7e", // Previously, entry_id }, "parent_object_id": "7298c9b4-63ac-4b7e-8a74-4468d2e403a9", // New "parent_record_id": "6003a6aa-7122-45f1-b840-efe9231dfd06", // New } ``` ### Step-by-step migration guide The following guide assumes you are implementing a zero downtime migration. You are, of course, welcome to migrate without such a constraint. 1. **Update your webhook server to handle V1 and V2 Events**. First, update the endpoints that handle the events we send you to deal with both V1 and V2 events.As there will be a brief overlap period where you receive both V1 and V2 events, you may wish to make your handler idempotent. 2. **Add new events**. Create new subscriptions to replace your old ones. For example, if you previously had a subscription on the `"entry.created"` event type, add a new one for the `"list-entry.updated"` event type. V1 subscriptions used a static `"collection_id"` property to limit subscriptions to a particular List (formerly “Collection”). This functionality can be replaced using our new filter functionality. For example, below is an example of a V1 subscription and its V2 replacement. These two subscriptions will respond to exactly the same changes in the system. ```json theme={"system"} // V1 { "event_type": "entry.created", "collection_id": "738eefb5-d481-4aed-9735-ce918f279b74" } // V2 { "event_type": "list-entry.created", "filter": { "$and": [ { "field": "id.list_id", "operator": "equals", "value": "d0a22439-5668-468a-b82a-f5988d9826f8" } ] } } ``` Any automated subscription creation using V1 APIs should be moved over to use V2 APIs. You should also move delete and update endpoints over to the V2 endpoints. 3. **Remove old events**. Your server should now be receiving both V1 and V2 events and responding to each correctly. Now that this is the case, you can go ahead and remove the V1 events using either the developer settings UI or the V1 delete endpoint. 4. **Clean up any V1 handling code**. Now that you are no longer receiving V1 events, you are welcome to clean up any code on your servers that handled the V1 events. # Overview Source: https://docs.attio.com/rest-api/overview Learn about the REST API Attio provides a public REST API which exchanges JSON over HTTPS. In this section, you will find guidance about working with the API. To get up and running, read our guide on [how to authenticate requests](/rest-api/how-to/authentication). From there, feel free to explore other topics or jump straight to the [reference documentation](/rest-api/endpoint-reference). * [Building an OAuth flow for your app](/rest-api/tutorials/connect-an-app-through-oauth) * [Working within our rate limits](/rest-api/how-to/rate-limiting) * [Setting up and listening to webhooks](/rest-api/how-to/webhooks) * [Filtering and sorting record and entry API queries](/rest-api/how-to/filtering-and-sorting) * [Paginating API responses](/rest-api/how-to/pagination) If you're looking to move beyond just the REST API and understand the Attio developer platform as a whole, you can find [general documentation for Attio developers here](/docs). # Connect an app to Attio through OAuth Source: https://docs.attio.com/rest-api/tutorials/connect-an-app-through-oauth Learn how to create an OAuth 2.0 app to access Attio's REST API If you're building an app that needs to make requests to Attio's REST API on behalf of many users, you should use OAuth 2.0 to authenticate your app. This tutorial will walk you through the process of modifying an example Node.js app to connect to Attio through OAuth. We'll start with a boilerplate app and modify it step-by-step to support generating an OAuth token for each user and then use that token to display a list of tasks they have in Attio. If you would prefer to jump straight ahead to reference information for each endpoint in our OAuth flow, you can find documentation [here](/rest-api/endpoint-reference/oauth-20/authorize-endpoint). Our next job is to enable OAuth 2.0 for the app. Head to the OAuth tab in your app's settings and enable OAuth 2.0 via the toggle at the top of the page. Next, configure the redirect URIs for your app. For our tutorial, we'll use the following URL: ``` http://localhost:3050/integrations/attio/callback ``` Of course, for a real app, you'd also include a publicly available URL such as `https://my-app.com/integrations/attio/callback`. Lastly, we need to configure the app's scopes. Heads to the scopes tab to enable these. For our demonstration app, we'll set tasks, user management, object configuration and records to "read" so we can fetch a list of tasks and which users they are assigned to. Make a new directory and setup your new Node.js project inside it: ```bash theme={"system"} mkdir my-app cd my-app npm init -y npm install express dotenv sqlite3 bcrypt express-session ``` Create a new file called `server.js` and add the following code: ```js theme={"system"} require("dotenv").config() const express = require("express") const session = require("express-session") const sqlite3 = require("sqlite3").verbose() const bcrypt = require("bcrypt") const app = express() const PORT = 3050 // NOTE: The following code is heavily simplified for educational purposes and should not be copied // for production use without careful consideration of security implications. // 1) Setup a database // Use ":memory:" for a temporary database in RAM. A real app should use a persistent database. const db = new sqlite3.Database(":memory:") // Seed a "users" table if it doesn't exist db.run(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, passwordHash TEXT NOT NULL ) `) // 2) Middleware // Enable parsing of form data app.use(express.urlencoded({extended: false})) // Setup session middleware app.use( session({ secret: "mysecret", // Replace with a strong secret in production resave: false, saveUninitialized: false, }) ) // 3) Page routes app.get("/", (req, res) => { if (req.session.userId) { return res.send(`

Welcome to Taskr!

You are logged in as ${req.session.username}.

Logout

`) } else { return res.send(`

You are not logged in

Sign Up

`) } }) app.get("/signup", (req, res) => { if (req.session.userId) { return res.redirect("/") } res.send(`

Sign Up





`) }) // 4) Endpoint routes app.post("/signup", async (req, res) => { const {username, password} = req.body try { const passwordHash = await bcrypt.hash(password, 10) // Hash the password for secure storage // Create a new user in the database db.run( `INSERT INTO users (username, passwordHash) VALUES (?, ?)`, [username, passwordHash], function (err) { if (err) { // If username is taken, sqlite typically throws a UNIQUE constraint error if (err.message.includes("UNIQUE constraint failed")) { return res.send(`

Username already taken

Try another username

`) } return res.send("An error occurred. Please try again.") } // If insert succeeds, log the user in req.session.userId = this.lastID // ID of the newly created user req.session.username = username // Show the home page return res.redirect("/") } ) } catch (error) { console.error("Error hashing password:", error) res.send("An error occurred. Please try again.") } }) app.get("/logout", (req, res) => { req.session.destroy(() => { res.redirect("/") }) }) // 4) Start the server app.listen(PORT, () => { console.log(`App running at http://localhost:${PORT}`) }) ``` You should now be able to run your app from the command line and visit it in your browser at `http://localhost:3050`: ```bash theme={"system"} node server.js ``` Run through the signup flow to ensure everything works as expected.
To add support for OAuth, we need to ensure that our Node.js code has access to the OAuth client ID and client secret. Create a new file called `.env` and add your app's client ID and client secret. You can find these in the OAuth tab in your app's settings. ``` ATTIO_CLIENT_ID=your-client-id ATTIO_CLIENT_SECRET=your-client-secret ``` When we complete the OAuth flow, we'll need a place to store the OAuth access token for each user. Modify the code that creates the `users` table as follows: ```js theme={"system"} db.run(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, passwordHash TEXT NOT NULL, attio_access_token TEXT ) `) ``` In a real app, you should encrypt these values before storing them. Access tokens are highly sensitive data and should be stored securely. Next, we need to implement the OAuth flow itself. An OAuth flow consists of the following steps: 1. Redirect to Attio's OAuth authorization page when prompted by the user 2. Handle the redirect back from Attio 3. Exchange the authorization code for an access token 4. Persist the access token 5. Make API requests using the access token ```mermaid theme={"system"} sequenceDiagram participant User participant Your App participant Attio User->>Your App: Click "Connect to Attio" Your App->>Attio: Redirect to OAuth authorization page Attio->>Your App: Redirect to app with authorization code Your App->>Attio: Exchange authorization code for access token securely Attio->>Your App: Return access token Your App->>Your App: Store access token Your App->>Attio: Make API request with access token ``` We'll start by adding a new route to our app that redirects the user to the OAuth authorization page. ```js theme={"system"} const crypto = require("crypto") app.get("/integrations/attio/connect", (req, res) => { if (!req.session.userId) { return res.redirect("/signup") // Must be logged in } // Generate a secure random state parameter and store it in the user's session const state = crypto.randomBytes(16).toString("hex") req.session.oauthState = state const authUrl = `https://app.attio.com/authorize?response_type=code&client_id=${process.env.ATTIO_CLIENT_ID}&redirect_uri=http://localhost:3050/integrations/attio/callback&state=${state}` res.redirect(authUrl) }) ``` A second route will handle the redirect back from Attio. ```js theme={"system"} const ATTIO_TOKEN_URL = "https://app.attio.com/oauth/token" app.get("/integrations/attio/callback", async (req, res) => { if (!req.session.userId) { return res.redirect("/signup") } const {code, state} = req.query // Verify the state parameter if (!state || state !== req.session.oauthState) { return res.status(403).send("Invalid state parameter. Possible CSRF attack detected.") } if (!code) { return res.status(400).send("Missing authorization code from Attio") } try { // Exchange authorization code for an access token using fetch const tokenResponse = await fetch(ATTIO_TOKEN_URL, { method: "POST", headers: {"Content-Type": "application/x-www-form-urlencoded"}, body: new URLSearchParams({ grant_type: "authorization_code", code: code, redirect_uri: "http://localhost:3050/integrations/attio/callback", client_id: process.env.ATTIO_CLIENT_ID, client_secret: process.env.ATTIO_CLIENT_SECRET, }), }) if (!tokenResponse.ok) { console.error("Attio token exchange failed with status:", tokenResponse.status) return res.status(500).send("Error exchanging code for token") } const tokenData = await tokenResponse.json() const attioAccessToken = tokenData.access_token // Update the user's record with the access token db.run( `UPDATE users SET attio_access_token = ? WHERE id = ?`, [attioAccessToken, req.session.userId], (err) => { if (err) { console.error("Failed to store Attio token in DB:", err) return res.status(500).send("Database error storing Attio token") } // Redirect back to home res.redirect("/") } ) } catch (err) { console.error("Error fetching token from Attio:", err) res.status(500).send("Internal error") } }) ``` Last, we need to ensure the user can navigate to the start of this flow. Let's add a button to the home page that redirects to the `/integrations/attio/connect` route. ```js theme={"system"} app.get("/", async (req, res) => { if (req.session.userId) { await db.get("SELECT * FROM users WHERE id = ?", [req.session.userId], async (err, user) => { if (err) { console.error("Error fetching users:", err) return res.status(500).send("Error fetching users") } const hasAttioConnection = user !== null && user.attio_access_token !== null return res.send(`

Welcome to Taskr!

You are logged in as ${req.session.username}.

Logout

${ hasAttioConnection ? `

Todo: render tasks

` : `

Connect Attio

` } `) }) } else { // ... } }) ``` Please note, the example above stores a raw access token in the database. The access tokens that we grant to your app are highly sensitive data and should be stored securely. Please ensure any production apps you build encrypt the token before storing it.
Now we have a token, all that remains is to make a request to the Attio API and render the results. To make a request to the Attio API, we need to call the right endpoint and pass in our new oauth token in the `Authorization` header like so. ```js theme={"system"} app.get("/", async (req, res) => { if (req.session.userId) { await db.get("SELECT * FROM users WHERE id = ?", [req.session.userId], async (err, user) => { if (err) { console.error("Error fetching users:", err) return res.status(500).send("Error fetching users") } const hasAttioConnection = user !== null && user.attio_access_token !== null if (hasAttioConnection) { const fetchResult = await fetch(`https://api.attio.com/v2/tasks?limit=10`, { headers: { Authorization: `Bearer ${user.attio_access_token}`, // Pass in the token here }, }) const data = await fetchResult.json() const taskItems = data.data.map((task) => { return `
  • ${task.content_plaintext}
  • ` }) const taskList = `
      ${taskItems.join("")}
    ` return res.send(`

    Welcome to Taskr!

    You are logged in as ${req.session.username}.

    Logout

    ${taskList} `) } return res.send(`

    Welcome to Taskr!

    You are logged in as ${req.session.username}.

    Logout

    Connect Attio

    `) }) } else { return res.send(`

    You are not logged in

    Sign Up

    `) } }) ```
    All that remains is to spin up your app and test it out! Run your app from the command line and visit it in your browser at `http://localhost:3050`. ```bash theme={"system"} node server.js ```
    # Call recording created Source: https://docs.attio.com/rest-api/webhook-reference/call-recording-events/call-recordingcreated https://api.attio.com/openapi/webhooks webhook call-recording.created This event fires after a call recording has finished and its media upload is complete. # Comment created Source: https://docs.attio.com/rest-api/webhook-reference/comment-events/commentcreated https://api.attio.com/openapi/webhooks webhook comment.created This event is fired whenever a comment is created. # Comment deleted Source: https://docs.attio.com/rest-api/webhook-reference/comment-events/commentdeleted https://api.attio.com/openapi/webhooks webhook comment.deleted This event is fired whenever a comment is deleted. # Comment resolved Source: https://docs.attio.com/rest-api/webhook-reference/comment-events/commentresolved https://api.attio.com/openapi/webhooks webhook comment.resolved This event is fired whenever a comment is resolved. # Comment unresolved Source: https://docs.attio.com/rest-api/webhook-reference/comment-events/commentunresolved https://api.attio.com/openapi/webhooks webhook comment.unresolved This event is fired whenever a comment is un-resolved. # List attribute created Source: https://docs.attio.com/rest-api/webhook-reference/list-attribute-events/list-attributecreated https://api.attio.com/openapi/webhooks webhook list-attribute.created This event is fired whenever a list attribute is created (e.g. adding an "Owner" attribute). # List attribute updated Source: https://docs.attio.com/rest-api/webhook-reference/list-attribute-events/list-attributeupdated https://api.attio.com/openapi/webhooks webhook list-attribute.updated This event is fired whenever a list attribute is updated (e.g. when changing the name of the "Owner" attribute to "Proprietor"). # List entry created Source: https://docs.attio.com/rest-api/webhook-reference/list-entry-events/list-entrycreated https://api.attio.com/openapi/webhooks webhook list-entry.created This event is fired whenever a list entry is created (i.e. when a record is added to a list). # List entry deleted Source: https://docs.attio.com/rest-api/webhook-reference/list-entry-events/list-entrydeleted https://api.attio.com/openapi/webhooks webhook list-entry.deleted This event is fired whenever a list entry is deleted (i.e. when a record is removed from a list). # List entry updated Source: https://docs.attio.com/rest-api/webhook-reference/list-entry-events/list-entryupdated https://api.attio.com/openapi/webhooks webhook list-entry.updated This event is fired whenever an existing list entry is updated (i.e. when a list attribute is changed for a specific list entry, e.g. when setting "Owner"). # List created Source: https://docs.attio.com/rest-api/webhook-reference/list-events/listcreated https://api.attio.com/openapi/webhooks webhook list.created This event is fired whenever a list is created. # List deleted Source: https://docs.attio.com/rest-api/webhook-reference/list-events/listdeleted https://api.attio.com/openapi/webhooks webhook list.deleted This event is fired whenever a list is deleted. # List updated Source: https://docs.attio.com/rest-api/webhook-reference/list-events/listupdated https://api.attio.com/openapi/webhooks webhook list.updated This event is fired whenever a list is updated (e.g. when changing the name or icon of the list). # Note content updated Source: https://docs.attio.com/rest-api/webhook-reference/note-content-events/note-contentupdated https://api.attio.com/openapi/webhooks webhook note-content.updated This event is fired whenever the content (body) of a note is updated. The `parent_object_id` refers to the object that the note references (e.g. the person object), and the `parent_record_id` refers to the record that the note references. # Note created Source: https://docs.attio.com/rest-api/webhook-reference/note-events/notecreated https://api.attio.com/openapi/webhooks webhook note.created This event is fired whenever a note is created. The `parent_object_id` refers to the object that the note references (e.g. the person object), and the `parent_record_id` refers to the record that the note references. # Note deleted Source: https://docs.attio.com/rest-api/webhook-reference/note-events/notedeleted https://api.attio.com/openapi/webhooks webhook note.deleted This event is fired whenever a note is deleted. # Note updated Source: https://docs.attio.com/rest-api/webhook-reference/note-events/noteupdated https://api.attio.com/openapi/webhooks webhook note.updated This event is fired whenever the title of a note is modified. Body updates do not currently trigger webhooks. # Object attribute created Source: https://docs.attio.com/rest-api/webhook-reference/object-attribute-events/object-attributecreated https://api.attio.com/openapi/webhooks webhook object-attribute.created This event is fired whenever an object attribute is created (e.g. when defining a new attribute "Rating" on the company object). # Object attribute updated Source: https://docs.attio.com/rest-api/webhook-reference/object-attribute-events/object-attributeupdated https://api.attio.com/openapi/webhooks webhook object-attribute.updated This event is fired whenever an object attribute is updated (e.g. when renaming the "Rating" attribute to "Score" on the company object). # Record created Source: https://docs.attio.com/rest-api/webhook-reference/record-events/recordcreated https://api.attio.com/openapi/webhooks webhook record.created This event is fired whenever a record is created. # Record deleted Source: https://docs.attio.com/rest-api/webhook-reference/record-events/recorddeleted https://api.attio.com/openapi/webhooks webhook record.deleted This event is fired whenever a record is deleted. # Record merged Source: https://docs.attio.com/rest-api/webhook-reference/record-events/recordmerged https://api.attio.com/openapi/webhooks webhook record.merged This event is fired whenever two records are merged together. Merging copies properties from the "duplicate" record into the original record, so that the original record has the properties of both, and the duplicate record is deleted. # Record updated Source: https://docs.attio.com/rest-api/webhook-reference/record-events/recordupdated https://api.attio.com/openapi/webhooks webhook record.updated This event is fired whenever an attribute on a record is updated (e.g. changing the "name" field on a record). # Task created Source: https://docs.attio.com/rest-api/webhook-reference/task-events/taskcreated https://api.attio.com/openapi/webhooks webhook task.created This event is fired whenever a task is created. # Task deleted Source: https://docs.attio.com/rest-api/webhook-reference/task-events/taskdeleted https://api.attio.com/openapi/webhooks webhook task.deleted This event is fired whenever a task is deleted. # Task updated Source: https://docs.attio.com/rest-api/webhook-reference/task-events/taskupdated https://api.attio.com/openapi/webhooks webhook task.updated This event is fired whenever a task is updated (e.g. the assignees or deadline are changed). # Workspace member created Source: https://docs.attio.com/rest-api/webhook-reference/workspace-member-events/workspace-membercreated https://api.attio.com/openapi/webhooks webhook workspace-member.created This event is fired whenever a workspace member is added to the workspace. # Source: https://docs.attio.com/sdk/components/avatar An avatar component for displaying profile pictures or organization logos. ```js theme={"system"} import {Avatar} from "attio/client" ``` ## Example ```jsx theme={"system"} ``` ## Props The name of the person or organization represented by the avatar. This is used for accessibility and may also be used as a fallback display when no image is provided. The source URL of the avatar image. If not provided or if the image fails to load, the avatar will typically display initials or a fallback representation based on the name. The shape of the avatar. Defaults to `'round'`. The visual variant of the avatar, affecting its styling and prominence. Defaults to `'bold'`. The size of the avatar. * `'small'` - `16px` * `'medium'` - `24px` * `'large'` - `32px` Defaults to `'medium'`. # Source: https://docs.attio.com/sdk/components/badge A colored badge of information. ```js theme={"system"} import {Badge} from "attio/client" ``` ## Example ```tsx TypeScript theme={"system"} import {Experimental_DescriptionList, Badge} from "attio/client" export function InformationDialog() { return ( Folklore Cornwall Paranormal ) } ``` ## Props The text in the badge. Only text is allowed. The color variant for the badge # Source: https://docs.attio.com/sdk/components/banner A component displaying important information to the user. export const ExperimentalWarning = ({api}) => The {api} API is experimental and may change in the future. It has been marked as @deprecated to remind the developer that it is experimental. It is not "deprecated", just experimental. Please don't use it in production versions of your app. We do not guarantee backward compatibility, or that the API will remain stable. ; ```js theme={"system"} import {Experimental_Banner} from "attio/client" ``` ```tsx TypeScript theme={"system"} import React from "react"; import { Experimental_Banner } from "attio/client"; export function HelloWorldDialog() { return ( <> {}}, {label: "Primary action", variant: "primary", onTrigger: () => {}}, ]} > Some important information with two actions ); } ``` ## Props The text of the banner. Only text is allowed. The variant of the banner. Optional actions to include. #