---
title: "Batch add or update user labels"
method: POST
path: "/v0/profiles/labels"
tags: ["Profiles"]
---

# Batch add or update user labels

`POST /v0/profiles/labels`

## Request

- Base URL: `https://api.formo.so`
- URL: `https://api.formo.so/v0/profiles/labels`
- Auth: HTTP bearer

Upsert up to 100 labels across many wallets in one request; each item carries its own `address`. Modelled on the events ingest API: rows with an invalid address (ENS names are NOT resolved here; pass a literal EVM `0x...` or Solana address) are quarantined (skipped and reported in the response) rather than failing the whole batch. A request where every row is invalid returns 400. Requires profiles:write scope. Batch delete: send rows with `_is_deleted: 1` to tombstone labels in bulk; omit `timestamp` to delete as of now, or pair it with a past `timestamp` to record a historical removal (the equivalent of DELETE /v0/profiles/{address}/labels, one row per wallet/label).

## Request body

- object[]
  - `tag_id` string, required: Label identifier (lowercased on write). e.g. vip, airdrop_eligible, coinbase.verified_account
  - `value` string: Optional label value (e.g. tier name, country code)
  - `chain_id` string: Optional chain identifier the label applies to
  - `timestamp` string, date-time: Optional ISO-8601 event-time for the label. When provided, the label is recorded at this time instead of the server's current time; used to backfill historical values (e.g. an `open_interest` reading from a past week) so label-based retention can evaluate them at the right point in time. Must not be in the future. Defaults to server time when omitted.
  - `_is_deleted` 0 | 1: Optional tombstone flag for backfilled removals. `1` records the row as a soft-delete (label removed) instead of a live value; pair it with a past `timestamp` to express "label removed at past time T" so point-in-time retention drops the wallet from that week. The future-timestamp guard still applies. Defaults to `0` (a live label) when omitted.
  - `address` string, required: Wallet address the label applies to. Literal EVM (0x...) or Solana address only; ENS names are not resolved in batch requests.

## Response `200`

Batch processed. Returns counts of forwarded vs quarantined rows, with a per-row `errors` entry for each quarantined row.

- BatchWriteResponse: Acknowledgement for a batch write. `successful_rows` counts rows accepted and forwarded to ingest after a 2xx (ingestion is async/eventually-consistent; there is no follow-up read). `quarantined_rows` counts rows skipped for an invalid address or no valid keys; `errors` (omitted when nothing was quarantined) maps each skipped row back to its request index.
  - `successful_rows` integer, required: Number of rows accepted and forwarded to ingest.
  - `quarantined_rows` integer, required: Number of rows skipped (invalid address, or no valid keys).
  - `errors` object[]: One entry per quarantined row. Omitted when quarantined_rows is 0.
    - `index` integer, required: Zero-based index of the row in the request array.
    - `address` string: The address as submitted, echoed back.
    - `reason` string, required: Why the row was quarantined.

## Other responses

- `400`: The request was rejected. `code` is either `INVALID_VALIDATION_REQUEST` (Zod schema mismatch; `details` carries a `{ fieldPath: message }` map) or `BAD_REQUEST` (semantic validation failure outside Zod, e.g. mismatched IDs, business-rule violations). Branch on `code`, not status, to tell the two apart.
- `401`: Missing or invalid API key.
- `403`: The API key is valid but lacks the required scope for this endpoint.
- `404`: The requested resource does not exist or is not visible to this API key's workspace.
- `429`: Per-workspace rate limit exceeded. Inspect the `RateLimit-*` response headers and back off.
- `500`: An unexpected error occurred on the server. The error has been logged; retry with exponential backoff.

---

[API](https://skmtc.dev/formo/apis/formo-public-api.md) · [All operations](https://skmtc.dev/formo/apis/formo-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/formo/apis/formo-public-api/revisions/67ada57df63c?raw)
