# Capability API recipes

These examples use current capability names and versions for documentation release `2026-08-11.3`. Fetch `/docs/openapi.json` or `/docs/reference/capabilities.md` before implementation and treat the generated schema as authoritative.

## Safe shell setup

Store the bearer token outside source code:

```sh
export DOMINO_TOKEN='YOUR_TOKEN_FROM_AGENT_ACCESS'
export DOMINO_API='https://letsdomino.io/api/v2'
```

Do not paste the real token into an AI conversation or commit it to a shell script.

Shared headers:

```sh
-H "Authorization: Bearer $DOMINO_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-Domino-Client: my-integration"
```

Writes additionally require a caller-stable `Idempotency-Key` header.

## Read calendar connection status

```sh
curl -sS "$DOMINO_API/capabilities/calendar.status.get" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "X-Domino-Client: my-integration" \
  -d '{"version":"1.0","input":{}}'
```

Check `status`, facts, disclosures, and management resources. The API can report connection state; Google OAuth and calendar-feed management remain web experiences.

## List people

```sh
curl -sS "$DOMINO_API/capabilities/relationships.people.query" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"version":"1.0","input":{"classification":"all","limit":25}}'
```

Use returned opaque person handles for later operations. For another page, pass the returned snapshot handle and cursor exactly. Never execute an internal numeric ID.

## Create an Ideas List

Read first with `ideas.lists.query@1.0` to avoid accidental duplicates. Then create:

```sh
curl -sS "$DOMINO_API/capabilities/ideas.lists.create" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: ideas-list-create-20260811-001" \
  -d '{
    "version":"2.0",
    "input":{
      "name":"North Side Weekends",
      "person_handles":["PERSON_HANDLE_FROM_DOMINO"],
      "neighborhood_names":["Lincoln Square"],
      "activity_names":["free things to do"],
      "directions":["Prefer places reachable by transit"],
      "apply_matching_likes":true
    }
  }'
```

Reuse the idempotency key only for an exact transport retry. If the user changes the name or defaults, use a new key.

## Search for a known object

`ideas.search` requires non-empty `query` or `q`:

```sh
curl -sS "$DOMINO_API/capabilities/ideas.search" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "version":"1.0",
    "input":{
      "query":"Lula Cafe",
      "scopes":["places","ideas"],
      "limit":10
    }
  }'
```

Use recommendations rather than lexical search for open-ended “what should we do?” requests.

## Get recommendations and continue a collection

Call `ideas.recommendations.get@2.1` with explicit people, required activities, neighborhoods, and user-supplied timing. Preserve qualitative modifiers in `preference_terms` rather than turning them into hard search terms.

If the outcome contains `has_more` and `next_cursor`, call the same capability with the returned cursor exactly. Do not reconstruct the prior constraints or rediscover solely to rebuild numbered options.

## Capture an idea and poll

Submit:

```sh
curl -sS "$DOMINO_API/capabilities/ideas.capture" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: capture-20260811-001" \
  -d '{
    "version":"2.0",
    "input":{
      "source_url":"https://example.com/place",
      "target_ideas_list_handle":"IDEAS_LIST_HANDLE_FROM_DOMINO"
    }
  }'
```

If the result is `accepted`, retain the returned capture public identifier and polling cursor. Observe it with `ideas.capture.get@1.0` or the returned status action. Do not create a second capture while the first is running.

If status is `needs_input`, present the exact question, obtain an answer, then make a new intentional call using the protected capture reference and current schema. Never guess identity details.

## Find availability

```sh
curl -sS "$DOMINO_API/capabilities/availability.query" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "version":"2.0",
    "input":{
      "when_preset":"this-weekend",
      "daily_start":"18:00",
      "daily_end":"22:00",
      "person_handles":["PERSON_HANDLE_FROM_DOMINO"],
      "limit":10
    }
  }'
```

Availability is privacy-safe free/busy output. Preserve unknown, partial, stale, and not-shared disclosures. Never infer event content.

## Create and prepare an invitation

### 1. Create the private draft

Use a candidate or place handle returned by authorized discovery:

```sh
curl -sS "$DOMINO_API/capabilities/plans.draft.create" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: plan-draft-20260811-001" \
  -d '{
    "version":"2.0",
    "input":{
      "candidate_id":"CANDIDATE_HANDLE_FROM_DOMINO",
      "scheduled_at":"2026-08-20T19:00:00-05:00",
      "rsvp_deadline":"2026-08-18T12:00:00-05:00",
      "capacity_min":2,
      "audience_selection":{
        "person_handles":["PERSON_HANDLE_FROM_DOMINO"]
      }
    }
  }'
```

This is a private write. Nobody has been invited.

### 2. Preview the draft

Call `plans.draft.preview@2.0` with the returned plan handle and a new idempotency key. Present all facts, recipients, and delivery disclosures.

### 3. Prepare sending

```sh
curl -sS "$DOMINO_API/capabilities/plans.prepare_send" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: plan-prepare-20260811-001" \
  -d '{
    "version":"2.0",
    "input":{
      "plan_handle":"PLAN_HANDLE_FROM_DOMINO",
      "action":"send_invites",
      "send_person_handles":["PERSON_HANDLE_FROM_DOMINO"]
    }
  }'
```

Present the exact prepared action and stop. Do not commit based on the original draft request.

### 4. Commit after later explicit approval

Use the exact prepared action handle with `actions.commit@1.0` from the same token/principal:

```sh
curl -sS "$DOMINO_API/capabilities/actions.commit" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: plan-commit-20260811-001" \
  -d '{
    "version":"1.0",
    "input":{"action_handle":"PREPARED_ACTION_HANDLE_FROM_DOMINO"}
  }'
```

Report only the terminal `effects.confirmed`. Preserve recipient-specific manual-share boundaries.

## Inspect, edit, or cancel an active plan

1. Use `plans.query@2.0`.
2. Inspect the selected returned plan with `plans.get@2.0`.
3. Use `plans.update.prepare@2.0` or `plans.cancel.prepare@2.0`.
4. Present the exact preparation.
5. Obtain later approval.
6. Commit with `actions.commit`.

On revision, recipient, or delivery-eligibility conflict, re-read current state and prepare again. Never commit a stale action handle.

## List invitations and RSVP

List current invitations with `invites.list@1.0`, optionally filtering `pending`, `accepted`, `declined`, or `removed`. Resolve the exact invite handle, then write the response:

```sh
curl -sS "$DOMINO_API/capabilities/invites.rsvp" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: invite-rsvp-20260811-001" \
  -d '{
    "version":"2.0",
    "input":{
      "invite_handle":"INVITE_HANDLE_FROM_DOMINO",
      "response":"accepted"
    }
  }'
```

Confirm the returned invitation state.

## Assistant API conversation

For natural-language interpretation, call:

```sh
curl -sS "$DOMINO_API/assistant/turns" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "message":"Find coffee with Andrew in the West Loop",
    "request_key":"turn-001",
    "channel_identity":"conversation-123"
  }'
```

Reuse a stable `channel_identity` for the same durable conversation. Use a unique request key for each intentional turn.

If the Assistant API returns a prepared action, ordinary text such as `SEND` cannot commit it. Present it, obtain later approval, then call:

```sh
export ACTION_HANDLE='PREPARED_ACTION_HANDLE_FROM_DOMINO'

curl -sS -X POST "$DOMINO_API/assistant/prepared-actions/$ACTION_HANDLE/commit" \
  -H "Authorization: Bearer $DOMINO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "request_key":"turn-002-commit",
    "channel_identity":"conversation-123"
  }'
```

Use the same channel identity as the preparation and a unique `request_key`.

## Status and error handling

- `completed`: present terminal confirmed facts.
- `unchanged`: explain that no new change was needed.
- `accepted`: poll the returned execution or status action.
- `needs_input`: obtain the missing decision and use a new intentional request.
- `failed`: follow normalized recovery guidance.
- HTTP `409`: inspect the conflict; do not blindly retry changed input under the same idempotency key.
- HTTP `429`: respect `Retry-After`.

## LLM and integration guidance

- Never embed secrets or internal IDs in examples shown to end users.
- Validate against generated schemas in CI.
- Log correlation and execution references securely, but base user-visible claims only on the canonical typed outcome.
- Separate plan drafting, preparation, approval, commit, and confirmed delivery in both code and UI.
