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

# Rotate secret

> Replace a webhook endpoint's signing secret. The old secret keeps signing for 24 hours, so you can switch your verifier without missing a delivery.

**Cost:** Free.

```bash
curl -X POST "https://api.alura.io/v1/webhooks/we_01JMOCK0000000000000000000/rotate-secret" \
  -H "Authorization: Bearer $ALURA_API_KEY" \
  -H "Idempotency-Key: 3f6c2a9e-1b4d-4c7a-9e2f-8d5b6a7c1e0f"
```

Needs the `webhooks:write` scope, and `orders:read` as well on an endpoint with order event types. The answer carries the new secret once.

## Switch without missing a delivery

For 24 hours, every delivery carries a signature from each secret: two in `webhook-signature`, separated by a space.

1. Rotate, and store the new secret.
2. Deploy your verifier with the new secret. Deliveries verify with either secret meanwhile, so the order of your deploys doesn't matter.
3. After 24 hours, deliveries carry only the new signature.

> [accordion] Rotating again within 24 hours
>
> The secret on its way out keeps its remaining time, and the one in between ends at once. A delivery never carries more than two signatures.

> [accordion] Retrying a rotation
>
> Send an `Idempotency-Key`. A retry with the same key answers the same secret instead of making another. See [Idempotency](https://docs.alura.io/api-reference/introduction.md#idempotency).

How signatures work is on [Verifying webhooks](https://docs.alura.io/guides/verifying-webhooks.md).


## OpenAPI

````yaml /openapi.json post /v1/webhooks/{id}/rotate-secret
openapi: 3.1.0
info:
  title: Alura API
  version: 1.0.0
  description: Etsy market research for scripts and AI assistants.
servers:
  - url: https://api.alura.io
security:
  - apiKey: []
paths:
  /v1/webhooks/{id}/rotate-secret:
    post:
      summary: Rotate secret
      description: >-
        Makes a new signing secret and answers it, once. The previous secret
        stays valid for 24 hours, and deliveries meanwhile carry a signature
        from each, so you can switch your verifier over without missing one.
        Rotating again within those 24 hours keeps the secret on its way out for
        its remaining time and ends the one in between at once. Retry safely
        with `Idempotency-Key`. Free.


        Cost: free.
      operationId: webhooks.endpoints.rotateSecret
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 64
            description: The webhook endpoint ID (`we_...`).
            example: we_01JMOCK0000000000000000000
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Makes a retry safe: the same key with the same request within 24
            hours returns the first result (with `Idempotent-Replayed: true`)
            instead of writing again. The same key with a different request is a
            409 `conflict`; while the first request still runs, 409
            `idempotency_processing`.
          schema:
            type: string
            minLength: 1
            maxLength: 255
      responses:
        '200':
          description: OK
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
            Alura-Credits-Cost:
              $ref: '#/components/headers/Alura-Credits-Cost'
            Alura-Credits-Remaining:
              $ref: '#/components/headers/Alura-Credits-Remaining'
          content:
            application/json:
              schema:
                type: object
                properties:
                  object:
                    type: string
                    const: webhook_endpoint
                  id:
                    type: string
                    description: '`we_...`'
                  url:
                    type: string
                    description: 'Where events are sent: an HTTPS URL.'
                  description:
                    description: Your note for this endpoint; null when none was set.
                    type:
                      - string
                      - 'null'
                  event_types:
                    type: array
                    items:
                      type: string
                    description: >-
                      Etsy's event types this endpoint receives: `*` for every
                      type, an exact type such as `order.paid`, or a prefix such
                      as `order.*`.
                  shop_ids:
                    anyOf:
                      - type: array
                        items:
                          type: string
                      - type: 'null'
                    description: >-
                      Only events of these connected shops; null for every
                      connected shop of the workspace, including shops connected
                      later.
                  status:
                    type: string
                    enum:
                      - enabled
                      - disabled
                    description: >-
                      `enabled` receives events; `disabled` receives none until
                      enabled again.
                  disabled_reason:
                    anyOf:
                      - type: string
                        enum:
                          - manual
                          - failing
                      - type: 'null'
                    description: >-
                      Why a disabled endpoint is disabled: `manual` (PATCH) or
                      `failing` (deliveries kept failing). Null while enabled.
                  created_at:
                    type: string
                    description: When the endpoint was created (ISO 8601, UTC).
                  secret:
                    type: string
                    description: >-
                      The signing secret (`whsec_...`). Shown once, in this
                      answer; store it to verify deliveries.
                required:
                  - object
                  - id
                  - url
                  - description
                  - event_types
                  - shop_ids
                  - status
                  - disabled_reason
                  - created_at
                  - secret
                additionalProperties: false
              example:
                object: webhook_endpoint
                id: we_01JMOCK0000000000000000000
                url: https://example.com/alura/webhooks
                description: Order notifications
                event_types:
                  - order.*
                shop_ids: null
                status: enabled
                disabled_reason: null
                created_at: '2026-10-22T09:00:00.000Z'
                secret: whsec_ExampleExampleExampleExampleExampleExam0=
        '400':
          $ref: '#/components/responses/Problem400'
        '401':
          $ref: '#/components/responses/Problem401'
        '402':
          $ref: '#/components/responses/Problem402'
        '403':
          $ref: '#/components/responses/Problem403'
        '404':
          $ref: '#/components/responses/Problem404'
        '405':
          $ref: '#/components/responses/Problem405'
        '409':
          $ref: '#/components/responses/Problem409'
        '429':
          $ref: '#/components/responses/Problem429'
        '500':
          $ref: '#/components/responses/Problem500'
        '503':
          $ref: '#/components/responses/Problem503'
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >-
            curl -X POST
            "https://api.alura.io/v1/webhooks/we_01JMOCK0000000000000000000/rotate-secret"
            \
              -H "Authorization: Bearer $ALURA_API_KEY" \
              -H "Idempotency-Key: 5f0c8e2a-4b1d-4c3e-9a7f-2b5d6e8f0a1c"
        - lang: typescript
          label: TypeScript
          source: >-
            const res = await
            fetch('https://api.alura.io/v1/webhooks/we_01JMOCK0000000000000000000/rotate-secret',
            {
              method: 'POST',
              headers: {
                Authorization: `Bearer ${process.env.ALURA_API_KEY}`,
                'Idempotency-Key': '5f0c8e2a-4b1d-4c3e-9a7f-2b5d6e8f0a1c',
              },
            });

            console.log(await res.json());
        - lang: python
          label: Python
          source: |-
            import json
            import os
            import urllib.request

            request = urllib.request.Request(
                "https://api.alura.io/v1/webhooks/we_01JMOCK0000000000000000000/rotate-secret",
                method="POST",
                headers={
                    "Authorization": f"Bearer {os.environ['ALURA_API_KEY']}",
                    "Idempotency-Key": "5f0c8e2a-4b1d-4c3e-9a7f-2b5d6e8f0a1c",
                },
            )
            with urllib.request.urlopen(request) as response:
                print(json.load(response))
components:
  headers:
    Request-Id:
      description: '`req_` + ULID; quote it when reporting a problem.'
      schema:
        type: string
    Alura-Credits-Cost:
      description: API credits this call cost.
      schema:
        type: integer
    Alura-Credits-Remaining:
      description: >-
        API credits left in the workspace's monthly allowance, counting calls
        still in flight. Absent when it cannot be read right now.
      schema:
        type: integer
  responses:
    Problem400:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/invalid_request
            title: Invalid request
            status: 400
            code: invalid_request
            detail: Invalid request
            suggestion: Fix the request as the detail says, then send it again.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem401:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/unauthorized
            title: Unauthorized
            status: 401
            code: unauthorized
            detail: Unauthorized
            suggestion: 'Send a valid API key as `Authorization: Bearer alura_sk_...`.'
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem402:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/credits_exhausted
            title: API credits exhausted
            status: 402
            code: credits_exhausted
            detail: API credits exhausted
            suggestion: Upgrade the plan or wait for the monthly reset.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem403:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/plan_required
            title: Plan required
            status: 403
            code: plan_required
            detail: Plan required
            suggestion: Upgrade the workspace plan to use this operation.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem404:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/not_found
            title: Not found
            status: 404
            code: not_found
            detail: Not found
            suggestion: Check the ID, or search for it first.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem405:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/method_not_allowed
            title: Method not allowed
            status: 405
            code: method_not_allowed
            detail: Method not allowed
            suggestion: Use one of the methods in the Allow header.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem409:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/conflict
            title: Conflict
            status: 409
            code: conflict
            detail: Conflict
            suggestion: Reload the resource and retry with its current state.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem429:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/rate_limited
            title: Rate limited
            status: 429
            code: rate_limited
            detail: Rate limited
            suggestion: Wait for Retry-After, then retry.
            retryable: true
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem500:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/internal_error
            title: Internal error
            status: 500
            code: internal_error
            detail: Internal error
            suggestion: Retry; if it keeps failing, report the request_id.
            retryable: true
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem503:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/credits_unavailable
            title: API credits unavailable
            status: 503
            code: credits_unavailable
            detail: API credits unavailable
            suggestion: Retry shortly.
            retryable: true
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
  schemas:
    Problem:
      type: object
      description: RFC 9457 problem details.
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        code:
          type: string
          description: A code from the error catalog; new codes may be added.
          x-extensible-enum:
            - invalid_request
            - unknown_parameter
            - invalid_cursor
            - cursor_window_exceeded
            - invalid_reference
            - id_type_mismatch
            - invalid_keyword
            - shop_id_required
            - listing_not_publishable
            - sales_window_not_covered
            - unauthorized
            - credits_exhausted
            - plan_required
            - insufficient_scope
            - workspace_required
            - workspace_locked
            - your_shop_unavailable
            - writes_suspended
            - browser_refused
            - role_required
            - impersonation_refused
            - recent_sign_in_required
            - etsy_scope_required
            - etsy_partner_required
            - not_found
            - not_collected
            - not_found_on_etsy
            - shop_opted_out
            - method_not_allowed
            - conflict
            - key_limit_reached
            - reconnect_required
            - settings_not_fetched
            - listing_busy
            - settings_busy
            - shop_create_busy
            - idempotency_partial_unverifiable
            - listing_has_variations
            - changed_since
            - change_not_revertable
            - listing_in_ab_test
            - activation_skipped
            - idempotency_processing
            - confirmation_required
            - test_shop_active_cap
            - write_outcome_unknown
            - unprocessable
            - listing_removed_on_etsy
            - endpoint_removed
            - rate_limited
            - throttled
            - daily_credit_cap_exceeded
            - credits_reserved
            - fetch_limit_reached
            - write_rate_limited
            - sync_cooldown
            - shop_write_budget_exhausted
            - internal_error
            - write_misconfigured
            - upstream_unavailable
            - credits_unavailable
            - service_unavailable
            - fetch_unavailable
            - create_lock_unavailable
            - writes_paused
            - etsy_capacity
            - upstream_timeout
        detail:
          type: string
        suggestion:
          type: string
        retryable:
          type: boolean
        request_id:
          type: string
        upgrade_url:
          type: string
          format: uri
          description: 'credits_exhausted and plan_required: where to upgrade the plan.'
        credits_needed:
          type: integer
          description: 'API credit refusals: what the call needed.'
        credits_remaining:
          type: integer
          description: >-
            API credit refusals: what is left (of the month, or of the day for
            daily_credit_cap_exceeded).
        resets_at:
          type: string
          format: date-time
          description: >-
            credits_exhausted and daily_credit_cap_exceeded: when the limit
            resets.
      required:
        - type
        - title
        - status
        - code
        - detail
        - suggestion
        - retryable
        - request_id
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: 'An API key: `Authorization: Bearer alura_sk_...`.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.