Perform a write action on a CRM resource.
Most actions require a two-call confirmation flow:
1. Call ``mutate`` without a ``confirmation_token`` — the server returns
a preview and a ``confirmation_token``.
2. Call ``mutate`` again with the same arguments PLUS the
``confirmation_token`` to commit the write.
Actions with ``min_confirmation: none`` execute in a single call.
Programmatic clients (API key / OAuth) may pass ``auto_confirm=True``
to skip confirmation for ``single_call_token`` actions.
Confirmation tier per action (B-15 — discoverable):
+-----------------------------------------+------------------------+
| Tier | Actions |
+-----------------------------------------+------------------------+
| NONE (single-call, no token needed) | contact.add_tag, |
| | contact.remove_tag, |
| | contact.add_note, | ← executes immediately
| | contact.add_interaction|
| | contact.update_*, |
| | company.add_tag, |
| | company.remove_tag, |
| | company.add_note, |
| | company.update_note, |
| | company.update.v1, |
| | deal.add_tag, |
| | deal.remove_tag, |
| | deal.move_stage, |
| | deal.update.v1, |
| | deal.add_note, |
| | deal.update_note, |
| | deal.add_contact, |
| | deal.remove_contact, |
| | reminder.* (act verbs) |
+-----------------------------------------+------------------------+
| SINGLE_CALL_TOKEN (preview + token) | contact.create, | ← returns confirmation_token
| | contact.add_email, | ← first call = preview only
| | contact.add_phone, | ← second call with token commits
| | contact.add_address, |
| | contact.add_job, |
| | contact.reactivate, |
| | contact.remove_email, |
| | contact.remove_phone, |
| | contact.remove_address,|
| | contact.remove_job, |
| | contact.remove_interaction, |
| | company.create, |
| | company.remove_note, |
| | deal.create, |
| | deal.remove_note, |
| | deal.update_record |
+-----------------------------------------+------------------------+
| BULK_CLEAR_ESCALATION (dynamic) | *.set_custom_field | ← NONE when <5 clears
| | (company/deal) | ← SINGLE_CALL_TOKEN when ≥5 clears
+-----------------------------------------+------------------------+
NONE-tier actions do NOT need auto_confirm=True — they always execute on the
first call. Only SINGLE_CALL_TOKEN actions need auto_confirm=True (or a
confirmation_token from the preview response) to commit.
Custom-field payload contract (B-10 — 4D-5250):
All ``*.set_custom_field.v1`` actions use ONE payload shape:
{<entity>_id, fields: [{custom_field_id: int, value: ...}, ...]}
- Only ``custom_field_id`` (int) is accepted — ``field_name`` / ``name``
/ ``id`` strings are rejected with ``validation.schema``. Enumerate
IDs via ``query("custom_fields", filters={"entity_type":"<entity>"})``.
- Per-kind ``value`` shape:
| Kind | Accepted ``value`` |
|------------------|------------------------------------------------------|
| Text / Long Text | str |
| URL | str (must be a URL the server accepts) |
| Number / Currency| int OR float OR decimal-shaped string |
| Date | ISO date "YYYY-MM-DD" OR epoch int |
| Select | option_id (int) OR label (str) |
| Multi Select | list[int|str] — option_ids OR labels |
| Contact Reference| contact_id (int) OR numeric string |
| Formula | REJECTED — validation.field_kind_readonly (B-25) |
- To clear a field: pass ``null`` (or ``""`` / ``"none"`` / ``[]`` per
kind — server normalises).
- Max 50 entries per batch, no duplicate ``custom_field_id``.
- Idempotency rule: B-1/B-2 (4D-5250) — repeating the same call with
the same ``idempotency_key`` returns
``{"replayed": true, "original_request_id": <uuid>, "result": <cached>}``.
For OAuth clients (Claude Desktop) replay is Valkey-only (24h TTL);
PAT clients additionally have a DB backstop.
Args:
action_key: Dotted action identifier, e.g. ``contact.add_note.v1``.
Omit the version suffix to use the latest version.
payload: Action-specific payload dict. Schema is validated
server-side; an invalid payload returns a
``validation.schema`` error.
target_type: Resource type of the target, e.g. ``contact``.
Required for actions that operate on a specific record.
target_id: Integer ID of the target record.
confirmation_token: Token returned by the preview call. Supply this
to commit the write after reviewing the preview.
idempotency_key: Client-generated unique key (UUID recommended).
Required for programmatic clients on create/update/delete.
Repeated calls with the same key replay the cached result.
if_match: Optimistic-concurrency version string for update-class
actions (e.g. contact.update_name.v1, company.update.v1,
deal.update.v1). Format: ``<resource>:<id>:<last_updated>``.
Collection-row actions (add/update/remove email, phone,
address, job, interaction) do NOT use if_match — passing
it has no effect; do NOT pass it for those actions (B-20).
auto_confirm: If ``True``, programmatic clients may skip the
confirmation step for ``single_call_token`` actions.
Has no effect on ``preview_required`` / ``human_required``
actions.
Returns:
One of:
- ``{confirmation_required: true, confirmation_token, preview, expires_at, fingerprint}``
— preview step, no write occurred.
- ``{request_id, result, audit_url}``
— write committed.
- ``{replayed: true, original_request_id, result}``
— idempotency replay (same result as first execution).
- ``{error: {code, message, http_status, ...}}``
— error envelope.
mutate