> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apostra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update signal

> Update signal metadata and manage access records

`PUT /api/v2/storefront/signals/{signalId}`

Updates a signal's metadata and access records. You can change `name`, `description`, and `isLive`, and add, update, or archive access records. `signalId`, `keyType`, `regions`, and `metadata` cannot change after creation.

<Warning>
  **Immutable fields are ignored, not rejected.** This endpoint accepts a closed
  set of fields. Send `keyType`, `regions`, or `metadata` and they are dropped
  before the write — the response is still `200` with the *unchanged* stored
  values, so a request that tried to change them looks like it succeeded. Send
  `signalId` in the body and it is overwritten by the id in the path, so it can
  never rename the signal or redirect the write to another one; the safest thing
  to send is the same id you addressed, or nothing.

  Read the response back and compare, rather than assuming a `200` means every
  field you sent was applied. To change a fixed field, archive the signal and
  register a replacement.
</Warning>

<Note>
  The in-chat signal tool guards this for you: it reads the stored signal first,
  lets an unchanged round-trip echo of the fixed fields through, and refuses a
  request that would actually change one — rather than reporting a save the API
  did not make.
</Note>

## Request

<CodeGroup>
  ```bash curl theme={null}
  curl -X PUT https://api.apostra.com/api/v2/storefront/signals/acme_high_value_customers \
    -H "Authorization: Bearer $SCOPE3_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "signalId": "acme_high_value_customers",
      "description": "Top 5% LTV customers, refreshed weekly",
      "isLive": true
    }'
  ```

  ```json Add and archive access theme={null}
  {
    "signalId": "acme_high_value_customers",
    "addAccess": [
      {
        "advertiserId": 90517,
        "visibility": "PROPRIETARY",
        "price": {
          "pricing_option_id": "po_cpm_partner",
          "pricing_model": "cpm",
          "currency": "USD",
          "fixed_price": 3.0
        }
      }
    ],
    "archiveAccess": [9001]
  }
  ```
</CodeGroup>

## Parameters

| Field           | Type       | Required | Notes                                                                                                                                                  |
| --------------- | ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `signalId`      | string     | Yes      | Signal identifier. **Overwritten by the path value**, so a differing body id is silently discarded rather than rejected — and never renames the signal |
| `name`          | string     | No       | New name (max 255)                                                                                                                                     |
| `description`   | string     | No       | New description (max 5000)                                                                                                                             |
| `isLive`        | boolean    | No       | Deploy or undeploy the signal                                                                                                                          |
| `addAccess`     | object\[]  | No       | New access records. Each requires `advertiserId` and `visibility`; optional `price`                                                                    |
| `updateAccess`  | object\[]  | No       | Existing access records to modify                                                                                                                      |
| `archiveAccess` | integer\[] | No       | Access record `id`s to archive                                                                                                                         |

## Response

```json theme={null}
{
  "signal": {
    "id": 50213,
    "signalId": "acme_high_value_customers",
    "customerId": 1001,
    "adcpAgentId": null,
    "name": "Acme — High-Value Customers",
    "description": "Top 5% LTV customers, refreshed weekly",
    "keyType": ["rampid", "uid2"],
    "regions": ["NORAM", "EMEA"],
    "metadata": null,
    "isLive": true,
    "archivedAt": null,
    "createdBy": "agent@acme.example",
    "updatedBy": "agent@acme.example",
    "createdAt": "2026-06-06T12:00:00Z",
    "updatedAt": "2026-06-06T14:30:00Z"
  },
  "access": [
    {
      "id": 9002,
      "signalId": 50213,
      "advertiserId": 90517,
      "visibility": "PROPRIETARY",
      "price": {
        "pricing_option_id": "po_cpm_partner",
        "pricing_model": "cpm",
        "currency": "USD",
        "fixed_price": 3.0
      },
      "archivedAt": null,
      "createdAt": "2026-06-06T14:30:00Z",
      "updatedAt": "2026-06-06T14:30:00Z"
    }
  ]
}
```

## Errors

* `400 VALIDATION_ERROR` — a malformed `signalId` (it must match `^[\w\-:.]+$` and be 1–255 characters), a field that breaks a length or enum constraint, or a body carrying **no** updatable field at all.
* `404 NOT_FOUND` — no signal with that `signalId` is visible to the authenticated account.

<Note>
  **These are not validation errors.** Sending `keyType`, `regions` or `metadata`
  does not fail — the fields are dropped before the write and the response is
  `200` with the unchanged stored values. A body `signalId` that differs from the
  path is not rejected either; it is overwritten by the path value. Both cases
  look like a successful update, which is why the Warning above tells you to read
  the response back and compare rather than trusting the status code.
</Note>

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Signal tasks" href="/v2/storefront/signals/tasks" icon="list-check">
    All signal operations
  </Card>

  <Card title="Get signal" href="/v2/storefront/signals/tasks/get-signal" icon="magnifying-glass">
    One signal with access records
  </Card>

  <Card title="Delete signal" href="/v2/storefront/signals/tasks/delete-signal" icon="trash">
    Archive a signal
  </Card>

  <Card title="Signal overview" href="/v2/object-guides/signal" icon="wave-pulse">
    Fields, lifecycle, and concepts
  </Card>
</CardGroup>
