---
title: "Edit or pause a micro-challenge template"
method: PATCH
path: "/campaigns/{campaign_id}/micro-challenges/{template_id}"
tags: ["Campaign Content & Challenges"]
---

# Edit or pause a micro-challenge template

`PATCH /campaigns/{campaign_id}/micro-challenges/{template_id}`

Partial update of a RECURRING template — name, window (`start_dow`/`start_time`/`end_dow`/`end_time`, or an equivalent nested `schedule` object), pricing, excluded creators, or `status: paused` to stop it producing new instances.

Affects FUTURE instances only: windows already materialized are never rewritten. When a not-yet-started instance exists for the template, it is returned as `already_scheduled_instance` so the caller can see what the edit did not touch. Ownership is enforced on the full (template, campaign, shop) triple — a template id from another campaign 404s.

Requires `read_write` scope and an `Idempotency-Key`; `X-Dry-Run: true` echoes the patch without applying it.

## Path parameters

- `campaign_id` integer, required
- `template_id` integer, required

## Headers

- `Idempotency-Key` string, nullable
- `X-Dry-Run` string, nullable

## Request body

- MicroChallengeTemplateUpdate — PATCH body for a recurring template (future instances only). Ownership fields are never read from the body -- the UPDATE's WHERE clause always uses the path/query-validated (template_id, campaign_id, shop_id) triple. The FE reuses its create serializer for edits, so it may send a nested ``schedule`` object; it is declared (accepted) and flattened into the flat fields the service reads.
  - `name` string, nullable
  - `schedule` union
    - MicroScheduleOneOff — A single explicit window (shop-local datetimes).
      - `mode` 'one_off'
      - `start_at` string, date-time, required
      - `end_at` string, date-time, required
    - MicroScheduleRecurring — A weekly recurring window. Day-of-week is 0=Mon..6=Sun; times are shop-local (the shop's timezone is resolved and stored at save time).
      - `mode` 'recurring'
      - `start_dow` integer, required
      - `start_time` string, time, required
      - `end_dow` integer, required
      - `end_time` string, time, required
  - `start_dow` integer, nullable
  - `start_time` string, time, nullable
  - `end_dow` integer, nullable
  - `end_time` string, time, nullable
  - `pricing` LeaderboardPricing — Pricing configuration for leaderboard campaigns. Extra keys are IGNORED (the codebase default, matching every sibling pricing class): the brand FE sends UI-only toggles like ``minimum_gmv_required_enabled`` that are not modelled here. The smuggling protection the materializer needs comes from re-parsing the stored template pricing through this model, which drops unknown keys so they never reach a materialized instance — not from ``extra="forbid"``, which would break the live create/edit path.
    - `campaign_type` 'leaderboard'
    - `leaderboard_ranks` LeaderboardRank[], required — At least one rank required
      - `rank` integer, required — Rank position (1-indexed)
      - `reward` union, required — Reward for this rank
        - number
        - string
    - `reward_type` 'cash' | 'custom', required — Reward payout mechanism.
    - `metric_type` 'gmv' | 'views' | 'videos_posted' | 'gmv_videos' | 'live_gmv' | 'gmv_and_live_gmv' | 'videos_gmv_and_live_gmv' — Performance metric to evaluate
    - `scoring_mode` 'single' | 'weighted' — Rank by a single metric or by a weighted composite score
    - `weighted_metrics` WeightedMetricItem[], nullable — Metric weights (must sum to 100) when scoring_mode is weighted
      - `metric_type` 'gmv' | 'avg_views_per_post' | 'views' | 'videos_posted' | 'units_sold' | 'live_gmv' | 'combined_gmv' | 'sessions', required — Metrics that can carry a weight in a weighted leaderboard. ``live_gmv`` is campaign-product-scoped LIVE GMV and ``combined_gmv`` is video GMV + that LIVE GMV as one dollar figure; a campaign weighting either must define ``product_ids`` (validated in LeaderboardPricing).
      - `weight` integer, required
    - `minimum_gmv_required` number, nullable — Minimum GMV threshold (when metric includes gmv)
    - `minimum_views_required` integer, nullable — Minimum views threshold (when metric is views)
    - `minimum_videos_required` integer, nullable — Minimum videos floor (gmv_videos gate; ranking stays by GMV)
    - `minimum_live_gmv_required` number, nullable — Minimum LIVE GMV floor (when metric is live_gmv)
    - `minimum_sessions_required` integer, nullable — Minimum LIVE sessions floor (weighted gate on a sessions weight)
  - `excluded_creator_ids` integer[], nullable
  - `status` 'active' | 'paused', nullable

## Response `200`

Successful Response

- unknown

## Other responses

- `400` — Validation error, multi-shop key, or missing `Idempotency-Key`.
- `403` — API key lacks `read_write` scope (`WRITE_NOT_PERMITTED`).
- `404` — Campaign / template / job not in this shop.
- `409` — Campaign results are final, campaign is LIVE-scored, template cap reached, or `Idempotency-Key` conflict.
- `422` — Validation Error
- `429` — Write-tier rate limit (10/min, 50/hr, 100/day) exceeded.

---

[API](https://skmtc.dev/reacherapp/apis/reacher-data-api.md) · [All operations](https://skmtc.dev/reacherapp/apis/reacher-data-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/reacherapp/reacher-data-api/revisions/578c830ce294/schema)
