Creators

Update a campaign

Updates a campaign from a partial spec: name, description, videoTarget, briefId and the schedule keys replace only what is present, payouts replaces the whole block. The payout rules are re-derived from the merged spec whenever the payouts sent differ from the current ones, or videoTarget or currency change (a rename, or the current payouts sent back unchanged, leaves them untouched) and apply to all unpaid billing windows immediately; issued payouts keep their stored snapshots. currency and the schedule are editable only while the campaign has no creator assignments or payout history (CAMPAIGN_FIELD_LOCKED otherwise; echoing the current value passes); the end date is managed by the end/reactivate endpoints. Dry-run with POST /campaigns/validate and an id to see which sentences would change.

put/campaigns/{id}

Request

  • Base URL: https://viral.app/api/v1
  • URL: https://viral.app/api/v1/campaigns/{id}
  • Auth: API key in header x-api-key

Path parameters

idstring required

Campaign ID with orgcamp_ prefix

Example:orgcamp_RwmraAffhMt9

Request body

namestring

Campaign name

descriptionstring

Campaign description

currency'USD' | 'EUR' | 'CHF' | 'GBP' | 'CNY' | 'JPY' | 'KRW' | 'THB' | 'IDR' | 'VND' | 'RUB'

Currency used for campaign payouts

videoTargetinteger

Expected number of videos per payment period

videoTargetUnit'videos' | 'creatives' | 'per_platform'

What the video target counts: "videos" (every post on every platform, a cross-post on three platforms counts 3), "creatives" (each video once, its copies on other platforms included) or "per_platform" (a count per platform in videoTargetPlatforms; videoTarget is their sum). Omitted: unchanged (sending videoTargetPlatforms alone switches to "per_platform"). Base payouts that stop following the target this way keep its current number as their own.

videoTargetPlatformsobject nullable

Videos per platform per cycle, for videoTargetUnit "per_platform" (e.g. {"tiktok": 30, "instagram": 30}). Posts on other platforms do not count toward the target.

briefIdstring nullable

Campaign brief ID with orgbrief_ prefix

notifyCreatorsOfBriefChangeboolean

When briefId links a (different) brief, notify the campaign's assigned creators about it. Removals never notify.

previewHashstring

The previewHash an edit dry-run returned for these exact changes. When present, a merged spec whose hash differs is refused (CAMPAIGN_PREVIEW_MISMATCH).

resetRemovedCustomRatesboolean

Consent to reset creators' custom rates on payouts this edit removes (the dry-run lists them in customRateImpact.resets). Without it such an edit fails with CUSTOM_RATES_RESET_REQUIRED.

Example request

{
  "name": "Updated Creator Rate",
  "description": "Updated notes"
}

Response

OK

idstring required

Campaign ID with orgcamp_ prefix

namestring required
descriptionstring nullable required
currency'USD' | 'EUR' | 'CHF' | 'GBP' | 'CNY' | 'JPY' | 'KRW' | 'THB' | 'IDR' | 'VND' | 'RUB' required
interval'day' | 'week' | 'month' required
intervalCountinteger required
billingAnchor'rolling' | 'fixed' required
timeZonestring required

IANA time zone the campaign's periods and dates follow (a period ends at midnight in this zone). Views are still counted per UTC day.

videoTargetinteger required

Videos per cycle in videoTargetUnit (with "per_platform": the sum of videoTargetPlatforms).

videoTargetUnit'videos' | 'creatives' | 'per_platform' required

What the video target counts: "videos" (every post on every platform, a cross-post on three platforms counts 3), "creatives" (each video once, its copies on other platforms included) or "per_platform" (a count per platform in videoTargetPlatforms; videoTarget is their sum).

videoTargetPlatformsobject nullable required

Videos per platform per cycle, with videoTargetUnit "per_platform"; null otherwise (create and update read a null sent back as none).

validFromstring date-time required
validUntilstring date-time nullable required
status'upcoming' | 'active' | 'closing' | 'ended' required

Campaign lifecycle status derived from validity window. upcoming: validFrom in the future; active: started with no end date; closing: started and has an end date in the present/future; ended: end date is in the past.

createdAtstring date-time required
updatedAtstring date-time required
orgIdstring required

Organization ID with org_ prefix

userIdstring required

User ID with user_ prefix

actorType'user' | 'system' | 'api_token' required
headlinestring required

One line: payouts and cadence, e.g. “€10.00 / video + CPM €1.00–€1.50 · monthly, rolling”.

hasPaidPeriodsboolean

A payout (not withdrawn) already priced this campaign's rules. Views conditions may still change, but thresholds are judged per video without memory: a raised one pays videos that were already paid again, a lowered one never pays earlier views of videos that newly qualify (updates return the views_conditions_changed_after_payouts warning). A changed total videos minimum, or a changed video target one follows, re-judges every period not paid yet (total_videos_changed_after_payouts).

conditionTagNamesobject

Names of the tags this campaign's payout conditions use, keyed by tag id. A tag that cannot be found in your organization is left out.

lockedFieldsstring[] required

Spec fields that can no longer change because the campaign has creator assignments or payout history. Sending their current value still passes.

Example response

{
  "id": "orgcamp_RwmraAffhMt9",
  "timeZone": "UTC",
  "videoTargetUnit": "videos",
  "status": "active",
  "spec": {
    "currency": "USD",
    "schedule": {
      "interval": "month",
      "intervalCount": 1,
      "anchor": "rolling",
      "startsOn": "2026-10-01",
      "timeZone": "UTC"
    },
    "videoTarget": 30,
    "videoTargetUnit": "videos",
    "briefId": "orgbrief_RwmraAffhMt9",
    "payouts": {
      "fixedSalary": {
        "id": "rule_A1b2C3d4E5f6"
      },
      "basePayouts": [
        {
          "id": "rule_A1b2C3d4E5f6",
          "perVideo": 10,
          "steps": [
            {
              "id": "rule_A1b2C3d4E5f6",
              "perVideo": 45
            }
          ],
          "minViews": 1000,
          "platforms": [
            "tiktok",
            "instagram"
          ],
          "conditions": {
            "match": "all",
            "items": [
              {
                "field": "contentType",
                "operator": "is",
                "values": [
                  "slideshow"
                ]
              },
              {
                "field": "views",
                "operator": "atLeast",
                "value": 10000
              }
            ]
          },
          "scope": "per_creative",
          "creatives": "once"
        }
      ],
      "cpmPayouts": [
        {
          "scope": "per_video",
          "creatives": "bestInWindow",
          "platforms": [
            "tiktok",
            "instagram"
          ],
          "conditions": {
            "match": "all",
            "items": [
              {
                "field": "contentType",
                "operator": "is",
                "values": [
                  "slideshow"
                ]
              },
              {
                "field": "views",
                "operator": "atLeast",
                "value": 10000
              }
            ]
          },
          "tiers": [
            {
              "id": "rule_A1b2C3d4E5f6",
              "to": 100000,
              "rate": 1
            }
          ]
        }
      ],
      "flatBonuses": [
        {
          "scope": "per_video",
          "creatives": "bestInWindow",
          "mode": "highest",
          "platforms": [
            "tiktok",
            "instagram"
          ],
          "conditions": {
            "match": "all",
            "items": [
              {
                "field": "contentType",
                "operator": "is",
                "values": [
                  "slideshow"
                ]
              },
              {
                "field": "views",
                "operator": "atLeast",
                "value": 10000
              }
            ]
          },
          "tiers": [
            {
              "id": "rule_A1b2C3d4E5f6",
              "to": 100000,
              "amount": 50
            }
          ]
        }
      ],
      "baseCap": {
        "id": "rule_A1b2C3d4E5f6"
      },
      "performanceCap": {
        "id": "rule_A1b2C3d4E5f6"
      },
      "eligibility": {
        "windowDays": 31,
        "publicationScope": "include_earlier"
      }
    }
  },
  "brief": {
    "id": "orgbrief_RwmraAffhMt9"
  },
  "warnings": [
    {
      "accounts": [
        {
          "platform": "facebook",
          "platformAccountId": "7123456789012345678"
        }
      ]
    }
  ]
}

Changes

No recorded changes to this operation across all 1 revision of this API.