# Perform an idempotent write

> Create one test dashboard through JSON:API, replay the identical request safely, and recognize a conflicting key reuse.

Create one harmless dashboard configuration, replay the identical request, and
prove that the second attempt does not create a duplicate. Use a disposable
non-production workspace and remove the test dashboard through the application
when finished.

## What you will do

1. Prepare one JSON:API dashboard document.
2. Send it with a stable `Idempotency-Key`.
3. Repeat the exact method, path, body bytes, and key.
4. Verify `idempotency-replayed: true`.
5. See why reusing that key for different input returns `409`.

## Prerequisites

- A service account in the test workspace with `api_write`.
- An active run-as member authorized to create dashboards.
- `HODOFLOW_BASE_URL`, `TOKEN`, cURL, and `jq`.
- A plan to delete the test dashboard in the Hodoflow application afterward.

Do not run this tutorial against production configuration. Read
[Scopes and run-as permissions](/authentication/scopes-and-permissions) before
granting write access.

## Request

Create the request body as a file so every retry uses identical bytes:

```bash
REQUEST_FILE="$(mktemp)"
IDEMPOTENCY_KEY="docs-dashboard-$(date -u +%Y%m%d)-001"

jq -n '{
  data: {
    type: "dashboard",
    attributes: {
      name: "API idempotency verification",
      description: "Disposable dashboard created by the developer guide"
    }
  }
}' > "$REQUEST_FILE"
```

Send the first request and keep its headers visible:

```bash
curl --silent --show-error --include \
  --request POST \
  --header "Accept: application/vnd.api+json" \
  --header "Content-Type: application/vnd.api+json" \
  --header "Authorization: Bearer $TOKEN" \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --data-binary "@$REQUEST_FILE" \
  "$HODOFLOW_BASE_URL/api/json/v1/dashboards"
```

Repeat that exact command without changing the file or key. Then, only as a
conflict exercise, change the dashboard name while keeping the old key and send
again. The changed request must not execute.

## Expected response

The first request returns `201` and one dashboard resource:

```json
{
  "data": {
    "type": "dashboard",
    "id": "00000000-0000-4000-8000-000000000001",
    "attributes": {
      "name": "API idempotency verification",
      "description": "Disposable dashboard created by the developer guide"
    }
  }
}
```

The identical replay returns the stored status and body with:

```http
idempotency-replayed: true
```

The altered body with the same key returns `409` and the stable
`idempotency_key_reused` code. It does not create or update another dashboard.
Keys are retained for 24 hours by default, though deployments can configure the
window.

## Troubleshooting

- `401`: exchange once, then retry with the same key and body.
- `403`: the account lacks `api_write`, the run-as member cannot create a
  dashboard, or a plan limit applies. Correct access; do not loop.
- `409 idempotency_key_in_progress`: wait briefly and repeat the identical request.
- `409 idempotency_key_reused`: reconcile the caller bug; do not hide it behind
  a new key.
- `422`: compare the body with the
  [create dashboard reference](/reference/json-api/dashboards/createDashboard).
- `429` or `5xx`: wait according to headers/backoff and retry with the same key.

Remove the temporary file and sensitive variables, then delete the test
dashboard through the application:

```bash
rm "$REQUEST_FILE"
unset REQUEST_FILE IDEMPOTENCY_KEY
```

## Next steps

- Apply the [idempotency and retry matrix](/platform/idempotency-retries) in your client.
- Browse exact [dashboard operations and fields](/reference/json-api/dashboards).
- Separate write credentials from read-only reporting credentials.
