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

# Update Subscription Preferences (V5)

> Partially updates a user's subscription preferences. The update is processed **asynchronously** by a separate worker, under the same SLA already communicated for this API; a successful call returns `202 Accepted`, not the updated resource.

`categories` is a sparse map — only the categories present in the request are changed; any category omitted is left unchanged. `is_globally_unsubscribed` is required on every call precisely because it has no neutral default: `true` unsubscribes the user from every category on the channel (and `categories` is ignored), while `false` clears any existing global unsubscribe.


#### Rate Limit

The rate limit is 100 RPM and 360k per day.


## OpenAPI

````yaml /api/subscription-categories/subscription-categories-v5/subscription-categories-v5.yaml patch /v5/subscription-preferences
openapi: 3.0.3
info:
  title: MoEngage Subscription Preferences API
  description: >
    Server-to-server API for reading and managing a user's Subscription Category
    preferences directly, without depending on MoEngage-hosted landing-page
    flows.


    This API provides endpoints for:

    * **List Subscription Categories**: Fetches the active subscription-category
    catalog for the workspace.

    * **Get Subscription Preferences**: Fetches a user's per-category
    subscription state and global unsubscribe status.

    * **Update Subscription Preferences**: Updates a user's per-category
    subscription state and/or global unsubscribe status.


    Users are identified by a `user_identifier_type` / `user_identifier_value`
    pair (`moe_user_id`, `uid`, or `email`), rather than a path parameter.


    **Transitional authentication note:** This route currently accepts HTTP
    Basic Auth only. Bearer token support is planned but not yet active on this
    path; Bearer requests return `401` until the APISIX gateway fronts this
    route.
  version: '2.0'
servers:
  - url: https://api-{dc}.moengage.com
    description: MoEngage API Server
    variables:
      dc:
        default: '01'
        description: >-
          The ‘dc’ in the API Endpoint URL refers to the MoEngage Data Center
          (DC). MoEngage hosts each customer in a different DC. You can find
          your DC number and replace the value of ‘dc’ in the URL by referring
          to the DC and API endpoint mapping
          [here](/api/introduction#data-centers). Your MoEngage Data Center (DC)
          can be 01, 02, 03, 04, 05, 06, or 101.
security:
  - basicAuth: []
tags:
  - name: Subscription Categories
    description: Fetch the active subscription-category catalog.
  - name: Subscription Preferences
    description: >-
      Fetch and update a user's per-category subscription state and global
      unsubscribe status.
paths:
  /v5/subscription-preferences:
    patch:
      tags:
        - Subscription Preferences
      summary: Update Subscription Preferences (V5)
      description: >
        Partially updates a user's subscription preferences. The update is
        processed **asynchronously** by a separate worker, under the same SLA
        already communicated for this API; a successful call returns `202
        Accepted`, not the updated resource.


        `categories` is a sparse map — only the categories present in the
        request are changed; any category omitted is left unchanged.
        `is_globally_unsubscribed` is required on every call precisely because
        it has no neutral default: `true` unsubscribes the user from every
        category on the channel (and `categories` is ignored), while `false`
        clears any existing global unsubscribe.
      operationId: updateSubscriptionPreferences
      parameters:
        - name: Accept
          in: header
          required: false
          schema:
            type: string
            example: application/json
        - name: Idempotency-Key
          in: header
          required: true
          description: >
            A UUID v4 you generate per logical update. Reusing a key with the
            same request body within the retention window returns the original
            response without reapplying the update. Reusing a key with a
            **different** request body returns `409`.
          schema:
            type: string
            format: uuid
        - name: MOE-APPKEY
          in: header
          required: true
          description: >
            This is the Workspace ID of your MoEngage account that must be
            passed with the request. You can find it in the MoEngage dashboard
            at Settings > Account > APIs > Workspace ID (earlier app id).
          schema:
            type: string
        - name: MOE-PROJECT-CODE
          in: header
          required: false
          description: >
            This is the project ID of your MoEngage account that must be passed
            with the request. You can find it in the MoEngage dashboard at
            Settings > Account > Portfolio > Project ID. Note: This parameter is
            mandatory for workspaces with the
            [Portfolio](/user-guide/settings/account/portfolio/portfolio)
            feature enabled.
          schema:
            type: string
        - name: X-MOE-Request-Id
          in: header
          required: false
          description: >
            Client-supplied trace ID for tracing. Correlates with `response_id`.
            Supply this header or `request_id` in the body; if both are set,
            they must match.
          schema:
            type: string
      requestBody:
        required: true
        description: >-
          The identifier of the user to update and the preference changes to
          apply.
        content:
          application/json:
            schema:
              type: object
              required:
                - user_identifier_type
                - user_identifier_value
                - is_globally_unsubscribed
              properties:
                request_id:
                  type: string
                  description: >-
                    Optional client-supplied request identifier, used for
                    tracing.
                  example: req_5b6d7a8f90c1e2b4d6f8091a2c3e4f56
                user_identifier_type:
                  type: string
                  enum:
                    - moe_user_id
                    - uid
                    - email
                  description: The type of identifier supplied in `user_identifier_value`.
                user_identifier_value:
                  type: string
                  description: >
                    The identifier value. For `moe_user_id`, accepts either the
                    `usr_`-prefixed ID or the bare 24-character hex ID.
                channel:
                  type: string
                  enum:
                    - email
                  description: >
                    Optional. The channel the `categories` map applies to. Only
                    the `email` channel is supported at present.
                is_globally_unsubscribed:
                  type: boolean
                  description: >
                    Required on every call. When `true`, the user is
                    unsubscribed from all categories on this channel, and
                    `categories` is ignored. Send `false` explicitly to clear an
                    existing global unsubscribe — there is no neutral default.
                categories:
                  type: object
                  description: >
                    Optional sparse map of `category_name` to subscribe state
                    (`true` = subscribed, `false` = unsubscribed). Only the
                    categories present here are changed; any category not
                    included is left unchanged.
                  additionalProperties:
                    type: boolean
                event_attributes:
                  type: object
                  description: >
                    Optional. Up to 5 name/value pairs attached to the
                    subscription-update event this call raises. Any attribute
                    name is accepted (no allowlist). Attribute names must be 50
                    characters or fewer; values must be 255 characters or fewer.
                  additionalProperties:
                    type: string
            example:
              user_identifier_type: email
              user_identifier_value: jane@example.com
              channel: email
              is_globally_unsubscribed: false
              categories:
                promotional: false
                newsletter: true
              event_attributes:
                source: preference_center
                campaign_ref: spring_sale
      responses:
        '202':
          description: >
            This response is returned when the request has been accepted and
            queued for asynchronous processing. The update is applied by a
            separate worker under SLA; this response does not confirm the update
            has been applied yet — poll Get Subscription Preferences to check
            the applied state.
          content:
            application/json:
              schema:
                type: object
                properties:
                  response_id:
                    type: string
                    description: Unique identifier for this API response.
                    example: resp_e474cbaf-2178-4e3a-816e-7575e1dc639b
                  type:
                    type: string
                    description: The resource type returned in `data`.
                    example: subscription_preference
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                        description: >-
                          A human-readable confirmation that the update was
                          accepted for processing.
                        example: Your request has been accepted and is being processed.
              example:
                response_id: resp_e474cbaf-2178-4e3a-816e-7575e1dc639b
                type: subscription_preference
                data:
                  message: Your request has been accepted and is being processed.
        '400':
          description: This response is returned when the request body is invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingValue:
                  summary: Missing Identifier Value
                  value:
                    error:
                      code: BAD_ARGUMENT
                      message: user_identifier_value is required
                      target: user_identifier_value
                tooManyAttributes:
                  summary: Too Many Event Attributes
                  value:
                    error:
                      code: BAD_ARGUMENT
                      message: A maximum of 5 event_attributes is allowed
                      target: event_attributes
                attributeTooLong:
                  summary: Attribute Name or Value Too Long
                  value:
                    error:
                      code: BAD_ARGUMENT
                      message: Invalid event_attributes
                      target: event_attributes
                unknownCategory:
                  summary: Unknown Category Name
                  value:
                    error:
                      code: BAD_ARGUMENT
                      message: Unknown category name(s)
                      target: categories
        '401':
          description: >-
            This response is returned when authentication is missing or invalid,
            or when a required workspace header is missing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                auth_required:
                  summary: Invalid or Missing Credentials
                  value:
                    error:
                      code: UNAUTHORIZED
                      message: Invalid or missing credentials
                      target: Authorization
                missing_project_code:
                  summary: Missing MOE-PROJECT-CODE Header
                  value:
                    error:
                      code: UNAUTHORIZED
                      message: MOE-PROJECT-CODE header missing
                      target: MOE-PROJECT-CODE
        '403':
          description: >-
            This response is returned when the credentials lack the required
            scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: FORBIDDEN
                  message: Token is missing required scope write:subscriptions
                  target: Authorization
        '404':
          description: This response is returned when the identifier resolves to no user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: NOT_FOUND
                  message: No user found for the given identifier
                  target: user_identifier_value
        '409':
          description: >-
            This response is returned when an email identifier matches multiple
            profiles with email-based unsubscribe disabled, or when the
            `Idempotency-Key` is reused with a different request body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                ambiguousEmail:
                  summary: Ambiguous Email Match
                  value:
                    error:
                      code: CONFLICT
                      message: >-
                        Multiple user profiles match this email; cannot update
                        unambiguously
                      target: user_identifier_value
                idempotencyKeyConflict:
                  summary: Idempotency Key Reused With Different Body
                  value:
                    error:
                      code: CONFLICT
                      message: >-
                        Idempotency-Key was already used with a different
                        request body
                      target: Idempotency-Key
        '413':
          description: This response is returned when the request payload is too large.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: PAYLOAD_TOO_LARGE
                  message: Request entity is too large
                  target: null
        '429':
          description: This response is returned when the rate limit has been exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: TOO_MANY_REQUESTS
                  message: Rate limit exceeded
                  target: null
        '500':
          description: >-
            This response is returned when the system runs into an unexpected
            error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: INTERNAL_SERVER_ERROR
                  message: Something went wrong, please retry
                  target: null
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: A machine-readable error code.
              example: BAD_ARGUMENT
            message:
              type: string
              description: A human-readable error message.
              example: user_identifier_type is not supported
            target:
              type: string
              nullable: true
              description: The field or header the error relates to, if any.
              example: user_identifier_type
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: >
        Authentication is done via Basic Auth. This requires a base64-encoded
        string of your credentials in the format 'username:password'.


        - **Username**: Your MoEngage app key.

        - **Password**: Your MoEngage API secret.


        **Transitional note:** This route currently accepts Basic Auth only.
        Bearer token support (`Authorization: Bearer <token>`) is planned but
        not yet active here — Bearer requests return `401` until the APISIX
        gateway fronts this route.


        For more information on authentication and getting your credentials,
        refer
        [here](https://www.moengage.com/docs/api/introduction#getting-your-credentials).

````