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

# Update a Webhook Subscription

> POST .../webhook/subscription/{SubscriptionId} — Partially updates a webhook subscription. Only supplied fields change; omitted fields keep current values.

Partially updates an existing webhook subscription. This is a patch-style operation — only fields you include in the request body are modified; any field you omit (or send as `null`) retains its current value. At least one field must be provided. You can use this endpoint to change the callback URL, update the event list, toggle the subscription on or off, or update the description.

<Note>
  The source API uses `POST` (not `PUT`) for this update operation. Use the path `POST /public/webhook/subscription/{SubscriptionId}`.
</Note>

<RequestExample>
  ```bash curl theme={null}
  curl -i -X POST \
    'https://api.portal.io/public/webhook/subscription/42' \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    -H 'X-MSS-API-APPID: YOUR_APP_ID' \
    -H 'X-MSS-API-USERKEY: YOUR_USER_KEY' \
    -H 'X-MSS-CUSTOM-DATE: Mon, 06 Apr 2026 00:22:19 GMT' \
    -H 'X-MSS-SIGNATURE: BASE64_SIGNATURE' \
    -d 'Url=https%3A%2F%2Fapp.example.com%2Fwebhooks%2Fportal-v2' \
    -d 'Enabled=true' \
    -d 'Events=proposal.status_changed' \
    -d 'Events=proposal.build.status_update' \
    -d 'Events=proposal.outline.status_update'
  ```

  ```python python theme={null}
  import requests
  from portal_auth import sign_request

  url = "https://api.portal.io/public/webhook/subscription/42"
  timestamp = "Mon, 06 Apr 2026 00:22:19 GMT"
  content_type = "application/x-www-form-urlencoded"
  signature = sign_request("POST", url, content_type, timestamp, "YOUR_USER_KEY", "YOUR_SECRET_KEY")

  response = requests.post(url, headers={
      "Accept": "application/json",
      "Content-Type": content_type,
      "X-MSS-API-APPID": "YOUR_APP_ID",
      "X-MSS-API-USERKEY": "YOUR_USER_KEY",
      "X-MSS-CUSTOM-DATE": timestamp,
      "X-MSS-SIGNATURE": signature
  }, data=[
      ("Url", "https://app.example.com/webhooks/portal-v2"),
      ("Enabled", "true"),
      ("Events", "proposal.status_changed"),
      ("Events", "proposal.build.status_update"),
      ("Events", "proposal.outline.status_update"),
  ])
  print(response.json())
  ```

  ```javascript node.js theme={null}
  const { signRequest } = require('./portalAuth');

  const url = "https://api.portal.io/public/webhook/subscription/42";
  const timestamp = new Date().toUTCString();
  const contentType = "application/x-www-form-urlencoded";
  const signature = signRequest("POST", url, contentType, timestamp, "YOUR_USER_KEY", "YOUR_SECRET_KEY");

  const response = await fetch(url, {
      method: "POST",
      headers: {
          "Accept": "application/json",
          "Content-Type": contentType,
          "X-MSS-API-APPID": "YOUR_APP_ID",
          "X-MSS-API-USERKEY": "YOUR_USER_KEY",
          "X-MSS-CUSTOM-DATE": timestamp,
          "X-MSS-SIGNATURE": signature
      },
      body: new URLSearchParams([
          ["Url", "https://app.example.com/webhooks/portal-v2"],
          ["Enabled", "true"],
          ["Events", "proposal.status_changed"],
          ["Events", "proposal.build.status_update"],
          ["Events", "proposal.outline.status_update"],
      ])
  });
  const data = await response.json();
  console.log(data);
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "subscriptionId": 42,
    "url": "https://app.example.com/webhooks/portal-v2",
    "description": "Production webhook",
    "enabled": true,
    "secretKey": "whsec_a1b2c3d4e5f6...",
    "events": [
      "proposal.status_changed",
      "proposal.build.status_update",
      "proposal.outline.status_update"
    ]
  }
  ```
</ResponseExample>


## OpenAPI

````yaml POST /public/webhook/subscription/{SubscriptionId}
openapi: 3.1.0
info:
  title: Portal.Api
  version: '1.0'
servers:
  - url: http://127.0.0.1:5000
security: []
tags: []
paths:
  /public/webhook/subscription/{SubscriptionId}:
    post:
      tags:
        - Webhooks
      summary: Update Webhook Subscription
      description: >-
        Partially updates an existing webhook subscription. Only supplied fields
        are changed; omitted (null) fields retain their current values. At least
        one field must be provided.
      operationId: UpdateWebhookSubscription
      parameters:
        - $ref: '#/components/parameters/Accept'
        - name: X-MSS-API-APPID
          in: header
          description: Application Id
          required: true
          schema:
            type: string
        - name: X-MSS-CUSTOM-DATE
          in: header
          description: A date timestamp of the request
          required: true
          schema:
            type: string
        - name: X-MSS-SIGNATURE
          in: header
          description: A signature for the request
          required: true
          schema:
            type: string
        - name: X-MSS-API-USERKEY
          in: header
          description: User API Key
          required: true
          schema:
            type: string
        - name: SubscriptionId
          in: path
          description: >-
            Numeric ID of the webhook subscription to update. Must belong to the
            authenticated account; returns 400 if not found.
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                Url:
                  description: >-
                    New HTTPS URL for the webhook endpoint. Must use the
                    https:// scheme and resolve to a publicly routable host —
                    private, loopback, and link-local addresses are rejected.
                    Omit (null) to keep the current URL.
                  type: string
                Description:
                  description: >-
                    New human-readable label for this subscription. Send an
                    empty string to clear the current description. Omit (null)
                    to keep the current value. Trimmed before storage.
                  type: string
                Enabled:
                  description: >-
                    When false, the subscription is paused and no events will be
                    delivered until re-enabled. Omit to leave the current state
                    unchanged.
                  type: boolean
                Events:
                  description: >-
                    Replacement list of event-type names. When provided,
                    completely replaces the existing event list. Omit to leave
                    the current list unchanged.
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscriptionResponse'
        '400':
          description: >-
            Validation failed. Common causes: subscription not found or does not
            belong to this account, URL is not HTTPS or resolves to a private
            address, unrecognised event names, or no changes were provided.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpError'
        '401':
          description: >-
            HMAC signature validation failed or credentials are invalid. Verify
            X-MSS-SIGNATURE, X-MSS-CUSTOM-DATE, and X-MSS-API-USERKEY headers.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpError'
        '402':
          description: >-
            The dealer's subscription is inactive or expired. An active
            subscription is required to use this endpoint.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpError'
        '403':
          description: You do not have permission for this action.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HttpError'
      deprecated: false
      x-codeSamples: []
components:
  parameters:
    Accept:
      name: Accept
      in: header
      description: Accept Header
      required: true
      schema:
        type: string
        enum:
          - application/json
  schemas:
    WebhookSubscriptionResponse:
      title: WebhookSubscriptionResponse
      required:
        - subscriptionId
        - url
        - enabled
        - events
      properties:
        subscriptionId:
          description: Unique numeric identifier of the webhook subscription
          type: integer
          format: int64
        url:
          description: HTTPS URL that receives webhook POST deliveries
          type: string
        description:
          description: Optional human-readable label for the subscription
          type: string
        enabled:
          description: Whether the subscription is enabled
          type: boolean
        secretKey:
          description: >-
            Signing secret used to verify webhook deliveries. Only returned when
            a new secret is issued, such as during create or update operations
          type: string
        events:
          description: Event names that trigger this subscription
          type: array
          items:
            type: string
      description: Webhook subscription returned by the public webhook management API
      type: object
    HttpError:
      title: HttpError
      properties:
        errorCode:
          type: string
        stackTrace:
          type: string
        contentType:
          type: string
        headers:
          $ref: '#/components/schemas/Dictionary_String_String_'
        cookies:
          type: array
          items:
            $ref: '#/components/schemas/Cookie'
        status:
          type: integer
          format: int32
        statusCode:
          type: string
        statusDescription:
          type: string
        response:
          $ref: '#/components/schemas/Object'
        responseFilter:
          $ref: '#/components/schemas/IContentTypeWriter'
        requestContext:
          $ref: '#/components/schemas/IRequest'
        paddingLength:
          type: integer
          format: int32
        resultScope:
          $ref: '#/components/schemas/Func_IDisposable_'
        options:
          $ref: '#/components/schemas/IDictionary_String_String_'
        responseStatus:
          $ref: '#/components/schemas/ResponseStatus'
        targetSite:
          $ref: '#/components/schemas/MethodBase'
        message:
          type: string
        data:
          $ref: '#/components/schemas/IDictionary'
        innerException:
          $ref: '#/components/schemas/Exception'
        helpLink:
          type: string
        source:
          type: string
        hResult:
          type: integer
          format: int32
      description: HttpError
      type: object
    Dictionary_String_String_:
      title: Dictionary<String,String>
      additionalProperties:
        type: string
      description: Dictionary<String,String>
      type: object
    Cookie:
      title: Cookie
      properties: {}
      description: Cookie
      type: object
    Object:
      properties: {}
      description: Object
      type: object
    IContentTypeWriter:
      title: IContentTypeWriter
      properties: {}
      description: IContentTypeWriter
      type: object
    IRequest:
      title: IRequest
      properties: {}
      description: IRequest
      type: object
    Func_IDisposable_:
      title: Func`1
      properties: {}
      description: Func<IDisposable>
      type: object
    IDictionary_String_String_:
      title: IDictionary<String,String>
      additionalProperties:
        type: string
      description: IDictionary<String,String>
      type: object
    ResponseStatus:
      title: ResponseStatus
      properties:
        errorCode:
          type: string
        message:
          type: string
        stackTrace:
          type: string
        errors:
          type: array
          items:
            $ref: '#/components/schemas/ResponseError'
        meta:
          $ref: '#/components/schemas/Dictionary_String_String_'
      description: ResponseStatus
      type: object
    MethodBase:
      title: MethodBase
      properties: {}
      description: MethodBase
      type: object
    IDictionary:
      title: IDictionary
      properties: {}
      description: IDictionary
      type: object
    Exception:
      title: Exception
      properties: {}
      description: Exception
      type: object
    ResponseError:
      title: ResponseError
      properties:
        errorCode:
          type: string
        fieldName:
          type: string
        message:
          type: string
        meta:
          $ref: '#/components/schemas/Dictionary_String_String_'
      description: ResponseError
      type: object

````