Functions for managing records within Attio objects.
Records are individual instances of an object — a specific person, company, or deal. Attribute values are passed and returned as plain maps keyed by attribute slug.
Authentication
Requires the record_permission:read scope for read operations and
record_permission:read-write for mutations.
Pagination
list/3 returns a single page. stream/3 lazily pages through all records
without buffering them in memory — compose it with Stream functions before
calling Enum.to_list/1 or similar to collect results:
client
|> Attio.Records.stream("people", limit: 100)
|> Stream.filter(fn r -> r["values"]["email_addresses"] != [] end)
|> Enum.to_list()If you want a plain {:ok, list} result rather than a lazy stream, use
stream_all/3:
{:ok, records} = Attio.Records.stream_all(client, "people")Attribute values
Attribute values in create/update requests are maps keyed by attribute slug. The structure of each value depends on the attribute type. For example:
%{
"name" => [%{"first_name" => "Alice", "last_name" => "Smith"}],
"email_addresses" => [%{"email_address" => "alice@example.com"}]
}Responses include an "attribute_type" field in each value that identifies
the type discriminator.
Summary
Functions
Creates a record if no match is found, or returns the existing matching record.
Creates a new record with the given attribute values.
Deletes a record.
Gets a single record by its ID.
Lists records for an object. Returns one page.
Returns a lazy stream of all records across all pages.
Fetches all records across all pages and returns them as a list.
Updates attribute values on an existing record.
Functions
@spec assert(Attio.Client.t(), String.t(), map()) :: {:ok, map()} | {:error, term()}
Creates a record if no match is found, or returns the existing matching record.
The supplied values are used as matching criteria. If exactly one record
matches, it is returned. If multiple records match, a 409 Conflict error is
returned. If no records match, a new record is created.
The response includes an "action" field: "created" or "updated".
Example
Attio.Records.assert(client, "people", %{
"email_addresses" => [%{"email_address" => "alice@example.com"}]
})
@spec create(Attio.Client.t(), String.t(), map()) :: {:ok, map()} | {:error, term()}
Creates a new record with the given attribute values.
Example
Attio.Records.create(client, "people", %{
"name" => [%{"first_name" => "Alice", "last_name" => "Smith"}],
"email_addresses" => [%{"email_address" => "alice@example.com"}]
})
@spec delete(Attio.Client.t(), String.t(), String.t()) :: {:ok, map()} | {:error, term()}
Deletes a record.
@spec get(Attio.Client.t(), String.t(), String.t()) :: {:ok, map()} | {:error, term()}
Gets a single record by its ID.
@spec list(Attio.Client.t(), String.t(), keyword()) :: {:ok, map()} | {:error, term()}
Lists records for an object. Returns one page.
Options
:limit- Number of records per page (1–1000, default 500).:cursor- Opaque pagination cursor from a previous response.
@spec stream(Attio.Client.t(), String.t(), keyword()) :: Enumerable.t()
Returns a lazy stream of all records across all pages.
Accepts the same options as list/3. Raises {:attio_stream_error, error}
on API failure mid-stream. Use stream_all/3 if you prefer a standard
{:ok, list} | {:error, term()} return value.
@spec stream_all(Attio.Client.t(), String.t(), keyword()) :: {:ok, [map()]} | {:error, Attio.Error.t() | Exception.t()}
Fetches all records across all pages and returns them as a list.
Accepts the same options as list/3. Returns {:ok, [map()]} on success
or {:error, term()} if any page request fails. Unlike stream/3, the
entire result set is loaded into memory.
Example
{:ok, records} = Attio.Records.stream_all(client, "people")
Updates attribute values on an existing record.
Only the supplied attributes are changed; others are left untouched.