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

# Update campaign

> Partially updates a campaign. Omitted fields are left unchanged.
`configuration.query` and `configuration.reviewer_assignment_policy`
cannot be updated after create; including either field returns 400.
`configuration.cron_expression` and
`configuration.recurring_duration_days` may only be set on template
campaigns; setting them on a one-off campaign returns 400.
`configuration.is_template` is immutable and not accepted on update.




## OpenAPI

````yaml https://app.opal.dev/openapi.yaml put /campaigns/{campaign_id}
openapi: 3.1.0
info:
  contact:
    email: hello@opal.dev
    name: Opal Team
    url: https://www.opal.dev/
  description: >-
    The Opal API is a RESTful API that allows you to interact with the Opal
    Security platform programmatically.
  title: Opal API
  version: '1.0'
servers:
  - description: Production
    url: https://api.opal.dev/v1
security: []
tags:
  - name: access-rules
    description: Operations related to access rules
  - name: apps
    description: Operations related to apps
  - name: bundles
    description: Operations related to bundles
  - name: campaigns
    description: Operations related to access review campaigns
  - name: configuration-templates
    description: Operations related to configuration templates
  - name: delegations
    description: Operations related to request reviewer delegations
  - name: event-streams
    description: Operations related to event streaming connections
  - name: events
    description: Operations related to events
  - name: groups
    description: Operations related to groups
  - name: group-bindings
    description: Operations related to group bindings
  - name: idp-group-mappings
    description: Operations related to IDP group mappings
  - name: message-channels
    description: Operations related to message channels
  - name: non-human-identities
    description: Operations related to non-human identities
  - name: on-call-schedules
    description: Operations related to on-call schedules
  - name: opal-queries
    description: Operations related to OpalQuery
  - name: owners
    description: Operations related to owners
  - name: requests
    description: Operations related to requests
  - name: resources
    description: Operations related to resources
  - name: sessions
    description: Operations related to sessions
  - name: tags
    description: Operations related to tags
  - name: tokens
    description: Operations related to API tokens
  - name: uars
    description: Operations related to UARs
  - name: users
    description: Operations related to users
paths:
  /campaigns/{campaign_id}:
    put:
      tags:
        - campaigns
      summary: Update campaign
      description: |
        Partially updates a campaign. Omitted fields are left unchanged.
        `configuration.query` and `configuration.reviewer_assignment_policy`
        cannot be updated after create; including either field returns 400.
        `configuration.cron_expression` and
        `configuration.recurring_duration_days` may only be set on template
        campaigns; setting them on a one-off campaign returns 400.
        `configuration.is_template` is immutable and not accepted on update.
      operationId: updateCampaign
      parameters:
        - description: The ID of the campaign.
          example: f454d283-ca87-4a8a-bdbb-df212eca5353
          explode: true
          in: path
          name: campaign_id
          required: true
          schema:
            type: string
            format: uuid
          style: simple
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCampaignInfo'
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Campaign'
          description: The updated `Campaign`.
      security:
        - BearerAuth: []
components:
  schemas:
    UpdateCampaignInfo:
      description: |-
        # UpdateCampaignInfo Object
        ### Description
        The `UpdateCampaignInfo` object is used to partially update a campaign.
        Omitted fields are left unchanged.

        ### Usage Example
        Use in the `PUT Campaign` endpoint.
      example:
        name: Q3 Access Review (Updated)
        configuration:
          end_date: '2026-09-30T00:00:00.000Z'
          timezone: America/Los_Angeles
      properties:
        name:
          description: The name of the campaign.
          example: Q3 Access Review (Updated)
          type: string
        configuration:
          description: Configuration fields to create or update.
          allOf:
            - $ref: '#/components/schemas/UpdateCampaignConfigurationInfo'
      type: object
    Campaign:
      description: An access review campaign.
      example:
        campaign_id: f454d283-ca87-4a8a-bdbb-df212eca5353
        name: Q3 Access Review
        status: DRAFT
        is_template: false
        created_at: '2026-07-01T00:00:00.000Z'
        updated_at: '2026-07-01T00:00:00.000Z'
        created_by_user_id: 32acc112-21ff-4669-91c2-21e27683eaa1
        configuration: null
        started_at: null
        started_by_user_id: null
        stopped_at: null
        stopped_by_user_id: null
        ended_at: null
        ended_by_user_id: null
      properties:
        campaign_id:
          description: The ID of the campaign.
          example: f454d283-ca87-4a8a-bdbb-df212eca5353
          format: uuid
          type: string
        name:
          description: The name of the campaign.
          example: Q3 Access Review
          type: string
        status:
          $ref: '#/components/schemas/CampaignStatusEnum'
        is_template:
          description: >-
            Whether this campaign is a recurring schedule template. Templates
            spawn draft campaigns on schedule rather than being reviewed
            directly.
          example: false
          type: boolean
        created_at:
          description: The creation time of the campaign.
          example: '2026-07-01T00:00:00.000Z'
          format: date-time
          type: string
        updated_at:
          description: The last updated time of the campaign.
          example: '2026-07-01T00:00:00.000Z'
          format: date-time
          type: string
        created_by_user_id:
          description: The ID of the user who created the campaign.
          example: 32acc112-21ff-4669-91c2-21e27683eaa1
          format: uuid
          type: string
        configuration:
          description: The campaign's configuration, if set.
          allOf:
            - $ref: '#/components/schemas/CampaignConfiguration'
          nullable: true
        started_at:
          description: The time the campaign was started, if started.
          example: '2026-07-02T00:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        started_by_user_id:
          description: The ID of the user who started the campaign, if started.
          example: 32acc112-21ff-4669-91c2-21e27683eaa1
          format: uuid
          nullable: true
          type: string
        stopped_at:
          description: The time the campaign was manually stopped, if stopped.
          example: '2026-07-10T00:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        stopped_by_user_id:
          description: The ID of the user who stopped the campaign, if stopped.
          example: 32acc112-21ff-4669-91c2-21e27683eaa1
          format: uuid
          nullable: true
          type: string
        ended_at:
          description: The time the campaign reached its scheduled end, if ended.
          example: '2026-07-14T00:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        ended_by_user_id:
          description: The ID of the user who ended the campaign, if ended.
          example: 32acc112-21ff-4669-91c2-21e27683eaa1
          format: uuid
          nullable: true
          type: string
      required:
        - campaign_id
        - name
        - status
        - is_template
        - created_at
        - updated_at
        - created_by_user_id
      type: object
    UpdateCampaignConfigurationInfo:
      description: |
        Configuration fields to update on a campaign. All fields are optional;
        omitted fields are left unchanged. `query` and
        `reviewer_assignment_policy` are set at create time and cannot be
        updated here; including either field returns 400.
        `cron_expression` and `recurring_duration_days` may only be set when
        the campaign is a template; setting them on a one-off campaign returns
        400. `is_template` is immutable and not accepted on update.
      example:
        end_date: '2026-09-30T00:00:00.000Z'
        timezone: America/Los_Angeles
        allow_self_review: false
      properties:
        allow_self_review:
          description: Whether reviewers can review their own access.
          example: false
          type: boolean
        send_reviewer_assignment_notification:
          description: Whether to notify reviewers upon assignment.
          example: true
          type: boolean
        allow_reviewer_reassignment:
          description: Whether reviewers may reassign their reviews to another user.
          example: false
          type: boolean
        start_date:
          description: |
            Scheduled start date of the campaign. May only be updated while the
            campaign has not started (started_at is null). When set, the date's
            calendar day in the campaign timezone must be at least tomorrow.
          example: '2026-07-02T00:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        end_date:
          description: |
            Scheduled end date of the campaign. When set, the date's calendar
            day in the campaign timezone must be at least tomorrow.
          example: '2026-09-30T00:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        timezone:
          description: >-
            IANA timezone used to interpret campaign deadlines (e.g.
            America/Los_Angeles).
          example: America/Los_Angeles
          type: string
        revoke_on:
          $ref: '#/components/schemas/CampaignRevokeOnEnum'
        reminder_schedule:
          description: Days before end date to send reminder notifications.
          example:
            - 7
            - 3
            - 1
          items:
            type: integer
          type: array
        reminder_include_manager:
          description: Whether to include the reviewer's manager in reminders.
          example: true
          type: boolean
        require_reason_on_denial:
          description: >-
            Whether reviewers must provide a reason when denying (revoking)
            access.
          example: false
          type: boolean
        hide_ai_suggestions:
          description: Whether AI suggestions are hidden from reviewers.
          example: false
          type: boolean
        custom_start_message:
          description: >-
            Optional custom message included when notifying reviewers that the
            campaign started.
          example: Please complete your reviews by Friday.
          nullable: true
          type: string
        group_asset_visibility_policy:
          $ref: '#/components/schemas/CampaignGroupAssetVisibilityPolicyEnum'
        cron_expression:
          description: >-
            Cron expression driving the recurring schedule. Only valid on
            template campaigns. Pass an empty string to clear the active months
            (next_scheduled_run is cleared); the campaign remains a template.
          example: 0 9 1 * *
          nullable: true
          type: string
        recurring_duration_days:
          description: >-
            Deadline window in days applied to each draft generated from this
            template. Only valid on template campaigns.
          example: 14
          nullable: true
          type: integer
      type: object
    CampaignStatusEnum:
      description: The current status of a campaign.
      enum:
        - DRAFT
        - ONGOING
        - COMPLETED
        - STOPPED
        - ENDED
      example: ONGOING
      type: string
    CampaignConfiguration:
      description: Configuration for an access review campaign.
      example:
        configuration_id: 39a4d283-ca87-4a8a-bdbb-df212eca5fdb
        created_at: '2026-07-01T00:00:00.000Z'
        updated_at: '2026-07-01T00:00:00.000Z'
        query: null
        reviewer_assignment_policy: MANUALLY
        allow_self_review: false
        send_reviewer_assignment_notification: true
        allow_reviewer_reassignment: false
        start_date: null
        end_date: '2026-09-30T00:00:00.000Z'
        timezone: America/Los_Angeles
        revoke_on: END
        reminder_schedule:
          - 7
          - 3
          - 1
        reminder_include_manager: true
        require_reason_on_denial: false
        hide_ai_suggestions: false
        custom_start_message: null
        group_asset_visibility_policy: STRICT
        is_template: false
        cron_expression: null
        next_scheduled_run: null
        last_scheduled_run: null
        recurring_duration_days: null
      properties:
        configuration_id:
          description: The ID of the campaign configuration.
          example: 39a4d283-ca87-4a8a-bdbb-df212eca5fdb
          format: uuid
          type: string
        created_at:
          description: The creation time of the configuration.
          example: '2026-07-01T00:00:00.000Z'
          format: date-time
          type: string
        updated_at:
          description: The last updated time of the configuration.
          example: '2026-07-01T00:00:00.000Z'
          format: date-time
          type: string
        query:
          description: >-
            Access-path query defining the scope of access to review. Uses the
            same principalFilter / entitlementFilter shape as ACCESS_PATH
            OpalQuery.
          allOf:
            - $ref: '#/components/schemas/OpalAccessPathQueryBody'
          nullable: true
        reviewer_assignment_policy:
          $ref: '#/components/schemas/UARReviewerAssignmentPolicyEnum'
        allow_self_review:
          description: Whether reviewers can review their own access.
          example: false
          type: boolean
        send_reviewer_assignment_notification:
          description: Whether to notify reviewers upon assignment.
          example: true
          type: boolean
        allow_reviewer_reassignment:
          description: Whether reviewers may reassign their reviews to another user.
          example: false
          type: boolean
        start_date:
          description: Scheduled start date of the campaign.
          example: '2026-07-02T00:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        end_date:
          description: Scheduled end date of the campaign.
          example: '2026-09-30T00:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        timezone:
          description: >-
            IANA timezone used to interpret campaign deadlines (e.g.
            America/Los_Angeles).
          example: America/Los_Angeles
          type: string
        revoke_on:
          $ref: '#/components/schemas/CampaignRevokeOnEnum'
        reminder_schedule:
          description: Days before end date to send reminder notifications.
          example:
            - 7
            - 3
            - 1
          items:
            type: integer
          type: array
        reminder_include_manager:
          description: Whether to include the reviewer's manager in reminders.
          example: true
          type: boolean
        require_reason_on_denial:
          description: >-
            Whether reviewers must provide a reason when denying (revoking)
            access.
          example: false
          type: boolean
        hide_ai_suggestions:
          description: Whether AI suggestions are hidden from reviewers.
          example: false
          type: boolean
        custom_start_message:
          description: >-
            Optional custom message included when notifying reviewers that the
            campaign started.
          example: Please complete your reviews by Friday.
          nullable: true
          type: string
        group_asset_visibility_policy:
          $ref: '#/components/schemas/CampaignGroupAssetVisibilityPolicyEnum'
        is_template:
          description: Whether this configuration is a recurring schedule template.
          example: false
          type: boolean
        cron_expression:
          description: >-
            Cron expression driving the recurring schedule. Null for one-off
            campaigns.
          example: 0 9 1 * *
          nullable: true
          type: string
        next_scheduled_run:
          description: Next time a draft will be generated from this template.
          example: '2026-08-01T16:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        last_scheduled_run:
          description: Most recent time a draft was generated from this template.
          example: '2026-07-01T16:00:00.000Z'
          format: date-time
          nullable: true
          type: string
        recurring_duration_days:
          description: >-
            Deadline window in days applied to each draft generated from this
            template.
          example: 14
          nullable: true
          type: integer
      required:
        - configuration_id
        - created_at
        - updated_at
        - reviewer_assignment_policy
        - allow_self_review
        - send_reviewer_assignment_notification
        - allow_reviewer_reassignment
        - timezone
        - revoke_on
        - reminder_include_manager
        - require_reason_on_denial
        - hide_ai_suggestions
        - group_asset_visibility_policy
        - is_template
      type: object
    CampaignRevokeOnEnum:
      description: When access decisions take effect during a campaign.
      enum:
        - ACTION
        - END
        - NONE
      example: END
      type: string
    CampaignGroupAssetVisibilityPolicyEnum:
      description: Controls what group assets reviewers can see during the campaign.
      enum:
        - STRICT
        - VIEW_VISIBLE_AND_ASSIGNED
        - VIEW_ALL
      example: STRICT
      type: string
    OpalAccessPathQueryBody:
      type: object
      description: >-
        Edge-query filters for an ACCESS_PATH OpalQuery. At least one of
        principalFilter or entitlementFilter is required.
      properties:
        principalFilter:
          $ref: '#/components/schemas/AccessEntityFilters'
        entitlementFilter:
          $ref: '#/components/schemas/AccessEntityFilters'
        accessLevelRemoteIds:
          type: array
          description: Filter by access-level remote IDs on the terminal edge.
          items:
            type: string
        accessLevelNames:
          type: array
          description: Filter by access-level display names on the terminal edge.
          items:
            type: string
        edgeFilter:
          $ref: '#/components/schemas/OpalAccessPathEdgeFilter'
    UARReviewerAssignmentPolicyEnum:
      description: >-
        A policy for auto-assigning reviewers. If auto-assignment is on,
        specific assignments can still be manually adjusted after the access
        review is started. Default is Manually. BY_OWNING_TEAM_ADMIN assigns
        reviews to resource admins in round-robin fashion.
        BY_OWNING_TEAM_ADMIN_ALL assigns reviews to all resource admins.
        BY_APPROVERS assigns reviews to resource approvers in round-robin
        fashion. BY_APPROVERS_ALL assigns reviews to all resource approvers.
      enum:
        - MANUALLY
        - BY_OWNING_TEAM_ADMIN
        - BY_OWNING_TEAM_ADMIN_ALL
        - BY_MANAGER
        - BY_APPROVERS
        - BY_APPROVERS_ALL
      example: MANUALLY
      type: string
    AccessEntityFilters:
      type: object
      description: >-
        Filters for matching entities by type, name, tag, IDs, connections, or
        access levels. Supports recursive logical composition via allOf/anyOf.
      properties:
        entityTypes:
          type: array
          description: >-
            Filter by entity type. Only RESOURCE, GROUP, and USER are queryable
            via OpalQuery.
          items:
            type: string
            enum:
              - RESOURCE
              - GROUP
              - USER
        entityItemTypes:
          type: array
          description: Filter by entity item types.
          items:
            $ref: '#/components/schemas/EntityItemTypeEnum'
        entityName:
          $ref: '#/components/schemas/EntityNameFilter'
        entityTag:
          $ref: '#/components/schemas/EntityTagFilter'
        entityIDs:
          type: array
          description: Filter by specific entity UUIDs.
          items:
            type: string
            format: uuid
        importedFromApp:
          type: array
          description: Filter by app IDs from which returned nodes will be imported from.
          items:
            type: string
            format: uuid
        roleRemoteIds:
          type: array
          description: >-
            Filter by role remote IDs. Can only be applied within a hasAccessTo
            clause.
          items:
            type: string
        roleNames:
          type: array
          description: >-
            Filter by role display names (e.g. "Admin", "Read"). Can only be
            applied within a hasAccessTo clause.
          items:
            type: string
        allOf:
          type: array
          description: |
            A list of nested filters that must all match (logical AND). Each
             item has the same shape as this object — scalar fields like
             `entityTypes` or `entityTag`, and can further nest `allOf`,
             `anyOf`, or `not`.
          items:
            $ref: '#/components/schemas/AccessEntityFilters'
        anyOf:
          type: array
          description: |
            A list of nested filters where at least one must match (logical
             OR). Each item has the same shape as this object.
          items:
            $ref: '#/components/schemas/AccessEntityFilters'
        not:
          description: >
            Excludes entities matching the embedded filter (logical NOT). Pass a
            filter object with the same shape as this one — typically a single
            scalar field, like `{not: {entityTypes: ["RESOURCE"]}}` to exclude
            resources.
          type: object
          x-go-type: AccessEntityFilters
    OpalAccessPathEdgeFilter:
      type: object
      description: Constraints on the access path edges themselves.
      properties:
        directOnly:
          type: boolean
          description: >-
            When true, only return direct (depth-1) principal-to-entitlement
            edges.
          example: true
        accessDurationType:
          type: string
          description: Constrain results by whether the terminal access expires.
          enum:
            - EXPIRING_ONLY
            - PERMANENT_ONLY
          example: EXPIRING_ONLY
    EntityItemTypeEnum:
      description: Granular subtype of an entity.
      enum:
        - USER
        - SERVICE_USER
        - ACTIVE_DIRECTORY_GROUP
        - AWS_SSO_GROUP
        - DUO_GROUP
        - GIT_HUB_TEAM
        - GIT_LAB_GROUP
        - GOOGLE_GROUPS_GROUP
        - GOOGLE_GROUPS_GKE_GROUP
        - LDAP_GROUP
        - OKTA_GROUP
        - OKTA_GROUP_RULE
        - TAILSCALE_GROUP
        - TWINGATE_GROUP
        - TWINGATE_GROUP_SYNCED
        - OPAL_GROUP
        - OPAL_ACCESS_RULE
        - AZURE_AD_SECURITY_GROUP
        - AZURE_AD_MICROSOFT_365_GROUP
        - CONNECTOR_GROUP
        - SNOWFLAKE_ROLE
        - WORKDAY_USER_SECURITY_GROUP
        - DATABRICKS_ACCOUNT_GROUP
        - AWS_IAM_ROLE
        - AWS_EC2_INSTANCE
        - AWS_EKS_CLUSTER
        - AWS_RDS_POSTGRES_INSTANCE
        - AWS_RDS_POSTGRES_CLUSTER
        - AWS_RDS_MYSQL_INSTANCE
        - AWS_RDS_MYSQL_CLUSTER
        - AWS_ACCOUNT
        - AWS_SSO_PERMISSION_SET
        - AZURE_MANAGEMENT_GROUP
        - AZURE_RESOURCE_GROUP
        - AZURE_SUBSCRIPTION
        - AZURE_VIRTUAL_MACHINE
        - AZURE_STORAGE_ACCOUNT
        - AZURE_STORAGE_CONTAINER
        - AZURE_SQL_SERVER
        - AZURE_SQL_MANAGED_INSTANCE
        - AZURE_SQL_DATABASE
        - AZURE_SQL_MANAGED_DATABASE
        - AZURE_USER_ASSIGNED_MANAGED_Identity
        - AZURE_ENTRA_ID_ROLE
        - AZURE_ENTERPRISE_APP
        - CUSTOM
        - CUSTOM_CONNECTOR
        - GCP_ORGANIZATION
        - GCP_BUCKET
        - GCP_COMPUTE_INSTANCE
        - GCP_BIG_QUERY_DATASET
        - GCP_BIG_QUERY_TABLE
        - GCP_FOLDER
        - GCP_GKE_CLUSTER
        - GCP_PROJECT
        - GCP_CLOUD_SQL_POSTGRES_INSTANCE
        - GCP_CLOUD_SQL_MYSQL_INSTANCE
        - GCP_SERVICE_ACCOUNT
        - GIT_HUB_REPO
        - GIT_HUB_ORG_ROLE
        - GIT_LAB_PROJECT
        - GOOGLE_WORKSPACE_ROLE
        - MONGO_INSTANCE
        - MONGO_ATLAS_INSTANCE
        - OKTA_APP
        - OKTA_ROLE
        - OPAL_ROLE
        - OPAL_SCOPED_ROLE
        - PAGERDUTY_ROLE
        - TAILSCALE_SSH
        - TWINGATE_RESOURCE
        - SALESFORCE_PERMISSION_SET
        - SALESFORCE_PROFILE
        - SALESFORCE_ROLE
        - SNOWFLAKE_DATABASE
        - SNOWFLAKE_SCHEMA
        - SNOWFLAKE_TABLE
        - WORKDAY_ROLE
        - MYSQL_INSTANCE
        - MARIADB_INSTANCE
        - POSTGRES_INSTANCE
        - TELEPORT_ROLE
        - DATABRICKS_ACCOUNT_SERVICE_PRINCIPAL
        - ILEVEL_ADVANCED_ROLE
      example: OPAL_ROLE
      type: string
    EntityNameFilter:
      type: object
      required:
        - stringMatchType
        - string
      description: Filters entities by name using a string match strategy.
      properties:
        stringMatchType:
          $ref: '#/components/schemas/StringMatchType'
        string:
          type: string
          description: The string value to match against the entity name.
          example: engineering
    EntityTagFilter:
      type: object
      required:
        - key
      description: >-
        Filters entities by a tag key/value pair, optionally scoped to a
        connection.
      properties:
        key:
          type: string
          description: The tag key to filter by.
          example: team
        value:
          type: string
          description: >-
            The tag value to filter by. If omitted, matches any value for the
            given key.
          example: platform
        connectionId:
          type: string
          format: uuid
          description: If specified, filters by tags associated with this connection.
    StringMatchType:
      type: string
      description: How to match a string value against entity names.
      enum:
        - CONTAINS
        - EQUALS
        - STARTS_WITH
        - ENDS_WITH
  securitySchemes:
    BearerAuth:
      scheme: bearer
      type: http

````