> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyreach.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Claiming rows

> Hand out one-time values like discount codes, without two conversations ever getting the same one.

Some data is meant to be given away once. A discount code, a trial licence, an appointment slot, a callback number from a pool.

The obvious approach — look one up, then mark it used — has a race in it. Two calls happening at the same moment both read the same unused code before either writes, and both callers are told the same thing. Nothing errors. You find out from redemption data.

**Claim** does the two steps as one, so that can't happen.

## What it does

You give it three things:

* **Filters** — which rows are eligible (`used = false`, `region = EU`)
* **Order** — which eligible row to prefer (cheapest first, oldest first)
* **Patch** — what to change on the row it takes (`used = true`)

It takes the first matching row, applies the patch, and returns the row. If two conversations claim at the same moment, the second one steps over the row the first is holding and takes the next — it doesn't wait, and it doesn't get a duplicate.

If nothing matches, it returns nothing. Running out is an answer your agent can speak, not an error.

## Setting one up

<Steps>
  <Step title="Add a column that marks the state">
    A Yes/no column like `used`, or a Date & time like `claimed_at`. Make sure every existing row has a value — a row where the column is missing or blank is invisible to the filter and can never be claimed.
  </Step>

  <Step title="Add the action to an agent tool">
    Add a **Custom Data** action, set the operation to **Claim**, and fill in the filters, order and patch.
  </Step>

  <Step title="Tell the agent when to use it">
    In the prompt. A claim is not reversible, so the agent should only reach for it when it's actually giving the value to the caller.
  </Step>
</Steps>

An example configuration:

```json theme={null}
{
  "type": "custom_data",
  "table": "discount_codes",
  "operation": "claim",
  "filters": [
    { "property": "used",   "op": "eq", "value": "false" },
    { "property": "region", "op": "eq", "value": "{{ arguments.get('region') }}" }
  ],
  "order":  [{ "property": "pct", "direction": "asc" }],
  "patch":  { "used": true }
}
```

That reads as: *take the lowest-percentage unused code in the caller's region, mark it used, and give it to me.*

## The model picks the row; you decide what happens to it

Filters can be templated from the agent's tool arguments, so the model chooses **which** row.

The **patch is fixed in the configuration** and can never come from the model. That asymmetry is the safety property: a model that could write the patch could set any field on any row it could find. It can ask for a code; it can't decide what "claiming" means.

Two rules on the patch:

* Only declared columns.
* Never the row key. Rewriting the key would leave the row's identity disagreeing with its contents.

## Filters and ordering

Claim speaks the same vocabulary as a search: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `contains`, `starts_with`, plus an order list. So "the cheapest unused code in this region" is one call, and anything you can express in a search filter you can express here.

Ordering is worth thinking about. With no order, rows come back in key order — which for sequential codes (`CODE-001`, `CODE-002`) means issuance is predictable. If that matters, order by something less guessable, or generate non-sequential codes.

## What to watch for

<Warning>
  **A claimed row stays claimed even if the call drops.** If the agent claims a code and the conversation ends before the caller hears it, that code is spent. For low-value codes that's usually fine. If it isn't, use a *reservation* instead: patch a `claimed_at` timestamp rather than a boolean, filter on rows where it's empty or older than your timeout, and sweep expired ones with a scheduled workflow.
</Warning>

**Watch the pool.** Nothing warns you that you're running low. If the supply matters, put a scheduled workflow on it that counts unclaimed rows and alerts you.

**Don't mirror a table you claim from.** The claim mark lives in the row itself, in the same place a full refresh overwrites. So if a scheduled import replaces the table's contents, every claimed row is quietly un-claimed — and the next caller is handed a code someone already has, which is the exact thing claiming exists to prevent. Nothing warns you, because a refresh cannot tell a claim mark from a genuine correction upstream.

Claim tables should be tables the platform owns: load them once, top them up with **Add or update**, never **Replace**.

## Checking what was handed out

Claiming sets the row's last-updated time, so the **Rows** tab sorted by claimed state shows you what's been issued and when. If you also patch something identifying — a conversation ID, a timestamp — you can reconcile against your own records later.

```json theme={null}
"patch": { "used": true, "claimed_at": "{{ conversation.created_at }}" }
```
