# `Attio.Records`
[🔗](https://github.com/sgerrand/ex_attio/blob/v0.2.0/lib/attio/records.ex#L1)

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.

# `assert`

```elixir
@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"}]
    })

# `create`

```elixir
@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"}]
    })

# `delete`

```elixir
@spec delete(Attio.Client.t(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

Deletes a record.

# `get`

```elixir
@spec get(Attio.Client.t(), String.t(), String.t()) :: {:ok, map()} | {:error, term()}
```

Gets a single record by its ID.

# `list`

```elixir
@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.

# `stream`

```elixir
@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.

# `stream_all`

```elixir
@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")

# `update`

```elixir
@spec update(Attio.Client.t(), String.t(), String.t(), map()) ::
  {:ok, map()} | {:error, term()}
```

Updates attribute values on an existing record.

Only the supplied attributes are changed; others are left untouched.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
