> For the complete documentation index, see [llms.txt](https://docs.themochi.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.themochi.app/common-tasks/update-lead-safely.md).

# Update a lead safely

A **write** changes Mochi data. The Mochi CLI is read-only, so use a reviewed direct API integration for writes. The connection needs `leads:write` for the selected organization. A general request to “integrate Mochi” is not permission to change customer data.

Use the [generated OpenAPI contract](https://openapi.gitbook.com/o/M0sgy6xKutCblHRqGmE5/spec/mochi-api.json) for exact paths, input fields, and response schemas.

## Follow this safety sequence

1. Read the lead and the current OpenAPI input schema.
2. Write a specific plan. Name the organization, lead ID, exact fields or manual tag, required scope, current state, idempotency key, failure behavior, verification, and rollback.
3. Obtain explicit approval for that plan.
4. Generate one UUID4 for the intended mutation. Preserve the same method, path, body, and `Idempotency-Key` if a documented retry is necessary.
5. Execute one mutation at a time and stop on an unexpected response.
6. Read the resource again and compare it with the approved target state.

Only manual tags can be added through this operation. Mochi may reject a contact overwrite. Do not bypass that conflict without a separate approved plan. Removing a tag with `suppress` also prevents future automatic tagging, so use it only when the user explicitly asks for that behavior.

## Add one approved manual tag

Set `MOCHI_LEAD_ID`, `MOCHI_TAG_ID`, and one caller-generated UUID4 in `MOCHI_IDEMPOTENCY_KEY`. These examples perform the same single mutation.

### cURL

```bash
curl --fail-with-body --silent --show-error \
  --request POST \
  --url "${MOCHI_BASE_URL}/v1/leads/${MOCHI_LEAD_ID}/tags/" \
  --header "Authorization: Bearer ${MOCHI_API_KEY}" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: ${MOCHI_IDEMPOTENCY_KEY}" \
  --data "{\"tag_id\": ${MOCHI_TAG_ID}}"
```

### Python

```python
import os

import requests

response = requests.post(
    f"{os.environ['MOCHI_BASE_URL']}/v1/leads/{os.environ['MOCHI_LEAD_ID']}/tags/",
    headers={
        "Authorization": f"Bearer {os.environ['MOCHI_API_KEY']}",
        "Idempotency-Key": os.environ["MOCHI_IDEMPOTENCY_KEY"],
    },
    json={"tag_id": int(os.environ["MOCHI_TAG_ID"])},
    timeout=30,
)
response.raise_for_status()
print({"status": response.status_code, "replayed": response.headers.get("Idempotent-Replay") == "true"})
```

### Node.js / TypeScript

```typescript
const baseUrl = process.env.MOCHI_BASE_URL ?? "https://api.themochi.app";
const response = await fetch(new URL(`/v1/leads/${process.env.MOCHI_LEAD_ID}/tags/`, baseUrl), {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.MOCHI_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": process.env.MOCHI_IDEMPOTENCY_KEY!,
  },
  body: JSON.stringify({ tag_id: Number(process.env.MOCHI_TAG_ID) }),
  signal: AbortSignal.timeout(30_000),
});
if (!response.ok) throw new Error(`Mochi HTTP ${response.status}`);
console.log({ status: response.status, replayed: response.headers.get("idempotent-replay") === "true" });
```

### PHP

```php
<?php
$baseUrl = getenv("MOCHI_BASE_URL") ?: "https://api.themochi.app";
$handle = curl_init($baseUrl . "/v1/leads/" . getenv("MOCHI_LEAD_ID") . "/tags/");
curl_setopt_array($handle, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("MOCHI_API_KEY"),
        "Content-Type: application/json",
        "Idempotency-Key: " . getenv("MOCHI_IDEMPOTENCY_KEY"),
    ],
    CURLOPT_POSTFIELDS => json_encode(["tag_id" => (int) getenv("MOCHI_TAG_ID")], JSON_THROW_ON_ERROR),
]);
$body = curl_exec($handle);
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
curl_close($handle);
if ($body === false || $status < 200 || $status >= 300) throw new RuntimeException("Mochi write failed");
echo json_encode(["status" => $status]);
```

## Partial failures and rollback

Do not continue to a second write after an unverified first write. For a successful wrong tag addition, remove that exact tag only after confirming it was introduced by this operation; decide separately whether suppression is intended. For stage, archive, or contact changes, record the non-sensitive prior value and use a separately approved compensating update when the current state still matches the value written by this integration.

Follow [Idempotency](/troubleshooting-and-safety/idempotency.md) and [Errors](/troubleshooting-and-safety/errors.md). Never generate a fresh idempotency key merely because the client timed out, and never retry an ambiguous mutation when current documentation does not define replay behavior.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.themochi.app/common-tasks/update-lead-safely.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
