# Favorite a Contributor Network item

```http
PUT /api/public/v1/contributor-network/items/{itemId}/favorite
```

**Scope**: `contributor-network.write`.

Sets one active public item as favorited for the API key owner. This is a kind-neutral community action, so the opaque `itemId` is sufficient; clients do not send Competition or kind assertions.

Competition enrollment is not required, but the account must have completed account setup.

## Path parameter

| Parameter | Requirement |
| :--- | :--- |
| `itemId` | **Required string.** Opaque Contributor Network item ID. |

## Request

The request has no body or query parameters. Do not send an `idempotencyKey`; the state transition is naturally idempotent.

```bash
export SAIR_API_BASE="https://api.sair.foundation/api/public/v1"

curl -X PUT \
  "$SAIR_API_BASE/contributor-network/items/$ITEM_ID/favorite" \
  -H "Authorization: Bearer $SAIR_API_KEY"
```

## Behavior

- The operation sets the caller's state to favorited; it never toggles an existing favorite off.
- The item and its owning Competition must still be publicly available when the update commits. Otherwise, no favorite is created and the endpoint returns `404 NOT_FOUND`.
- Repeating the same request keeps one favorite for the `(API key owner, itemId)` pair. It does not increment the count again.

## Response

Returns `200 OK`:

```json
{
  "ok": true,
  "data": {
    "favorited": true,
    "favoriteCount": 5
  }
}
```

`favorited` is always `true`. `favoriteCount` is the item's total immediately after this transition; another account may change that total before a later read.

Successful responses use `Content-Type: application/json` and `Cache-Control: private, no-store` because the result contains caller-specific state.

## Errors

| HTTP | Code | When |
| :---: | :--- | :--- |
| `400` | `MALFORMED_BODY` | The request contains a body, a query parameter, or another unsupported top-level request field. |
| `403` | `ACCOUNT_INITIALIZATION_REQUIRED` | The API key owner has not completed account setup. |
| `404` | `NOT_FOUND` | The item or its owning Competition does not exist or is not active and publicly visible. |

See [Errors](../../errors.md) for shared errors.
