---
title: "Validate custom rates (dry-run)"
method: POST
path: "/campaigns/{id}/custom-rates/validate"
tags: ["Creators"]
---

# Validate custom rates (dry-run)

`POST /campaigns/{id}/custom-rates/validate`

## Request

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

Validates custom rates for one or more creators on the campaign exactly as the write would, without writing: per creator every value that changes, the existing custom values a merge replaces, warnings about odd values, and for a single creator their unpaid periods priced before and after. Pass the previewHash to the write to make sure it writes what was reviewed.

## Path parameters

- `id` string, required: Campaign ID with orgcamp_ prefix

## Request body

- object
  - `creatorIds` string[], required: The creators the values are for (assigning several creators at once: up to 50).
  - `mode` 'replace' | 'merge': replace: the values become the creator's whole set (the custom-rates write). merge: they are merged into each creator's existing values (assigning or switching with customRates).
  - `videoTarget` integer, nullable: The creator's own video target per cycle, in the campaign's unit (videos or creatives; per-platform campaigns use videoTargetPlatforms). Setting replaces their set (PUT): omitted or null follows the campaign's. Assigning merges: omitted or null keeps what they have, the campaign's own value resets it. A base payout capped at the campaign target is capped at this one instead.
  - `videoTargetPlatforms` object, nullable: For a campaign whose video target counts per platform: the creator's own count per platform (only the campaign's platforms; one left out follows the campaign's), with the same replace and merge rules as videoTarget. E.g. {"tiktok": 20}.
  - `values` object[]: The creator's custom values. A payout left out pays the campaign's value.
    - `id` string, required: The payout's id from the campaign spec: a base payout, a CPM or bonus tier, the fixed salary or the performance cap.
    - `field` 'perVideo' | 'videoCap' | 'amountCap' | 'rate' | 'amount', required: perVideo, videoCap or amountCap on a base payout; rate on a CPM tier; amount on a bonus tier, the fixed salary or the performance cap.
    - `value` number, required: Major units of the campaign currency (a video count for videoCap). 0 switches that payout off for the creator; caps stay above 0.

## Response `200`

OK

- object: Dry-run of custom rates: what changes, warnings, and a previewHash.
  - `ok` boolean, required
  - `issues` object[], required
    - `path` string, required
    - `message` string, required
  - `previewHash` string
  - `currency` string
  - `creators` object[]
    - `creator` object, required
      - `id` string, required: Organization creator ID with orgcre_ prefix
      - `userId` string, required: User ID with user_ prefix
      - `name` string, nullable, required
      - `email` string, required
      - `image` string, nullable, required
      - `archived` boolean, required
    - `changes` object[], required: Every value that changes against what the creator is paid now.
      - `key` string, required
      - `group` string, required
      - `label` string, required
      - `before` string, required
      - `after` string, required
    - `replaced` object[], required: Merge only: the creator's existing custom values this replaces.
      - `key` string, required
      - `group` string, required
      - `label` string, required
      - `before` string, required
      - `after` string, required
    - `warnings` string[], required
    - `openWindows` object[], nullable, required: The creator's unpaid periods on the campaign with their amounts (major units) before and after. Single creator only; null when not priced.
      - `billingPeriodStart` string, required
      - `billingPeriodEnd` string, required
      - `status` 'due' | 'upcoming', required
      - `currency` string, required
      - `before` number, nullable, required
      - `after` number, nullable, required

## Other responses

- `400`: 400
- `401`: 401
- `402`: 402
- `404`: 404
- `408`: 408
- `429`: 429
- `500`: 500

---

[API](https://skmtc.dev/viral/apis/viral-app-api.md) · [All operations](https://skmtc.dev/viral/apis/viral-app-api/llms.txt) · [OpenAPI document](https://skmtc.dev/viral/apis/viral-app-api/revisions/31e97fa79ef1?raw)
