> For the complete documentation index, see [llms.txt](https://help.openloyalty.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.openloyalty.io/api-reference/campaign/add-a-new-campaign.md).

# Add a new campaign

Management\
\
This method allows creating a new Campaign.\
\
**Custom-fields semantics on POST:**

* `customFields` omitted, `null`, or `{}` → the campaign is created with no custom-field values; required-field validation still runs and the request fails with 400 if any active campaign custom-field group contains a required field.
* `customFields: { groupKey: { fieldKey: value, ... }, ... }` → the provided values are persisted on the new campaign; required-field validation runs against the payload.

The feature flag `CUSTOM_FIELD_CAMPAIGN` must be enabled; when disabled the `customFields` key is silently ignored.

````json
{"openapi":"3.0.0","info":{"title":"Open Loyalty","version":"0.0.1"},"tags":[{"name":"Campaign","description":"These endpoints will allow you to easily manage campaigns."}],"servers":[{"url":"http://openloyalty.localhost"}],"security":[{"Bearer":[]},{"token":[]}],"components":{"securitySchemes":{"Bearer":{"type":"http","description":"Open Loyalty has the JWT authorization.\nTo learn what a JSON Web Token is and how it works, check out Introduction to JSON Web Tokens <https://jwt.io/introduction/>\n\n### Obtain an access token\n\nSend a request with the parameters username and password\n\n#### Definition\n\n`POST /api/admin/login_check` [Go to definition](#operation/adminLoginCheck)\\\n`POST /api/{storeCode}/member/login_check` [Go to definition](#operation/memberLoginCheck)\n\n#### Example\n\n```bash\ncurl {HOST}/api/admin/login_check\n    -H 'Content-Type: application/json;charset=UTF-8'\n    -H 'Accept: application/json, text/plain, */*'\n    --data-binary '{\"username\":\"admin\",\"password\":\"password\"}'\n```\n\n#### Example Response\n\n```json\n{\n    \"token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6...\",\n    \"refresh_token\":\"0558f8bb29948c4e54c443f...\"\n}\n```\n\n### Using JSON Web Token\n\nAdd authorization header to each request\\\n`Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...`\\\nYou can now access any API method you want under the /api prefix.\n\n#### Example\n```bash\ncurl {HOST}/api/{storeCode}/analytics/members\n    -H 'Accept: application/json'\n    -H 'Content-type: application/x-www-form-urlencoded'\n    -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...'\n```\n\n### Refresh JSON Web Token\nYou can refresh token using refresh_token that was given during login.\\\nThere are two endpoints\\\nTo refresh admin token `POST /api/token/refresh` [Go to definition](#operation/tokenRefresh)\\\nTo refresh member token `POST /api/{storeCode}/token/refresh` [Go to definition](#operation/tokenRefreshMember)\n","bearerFormat":"JWT","scheme":"bearer"},"token":{"type":"apiKey","name":"X-AUTH-TOKEN","in":"header"}},"parameters":{"storeCode":{"name":"storeCode","in":"path","description":"Store code","required":true,"schema":{"type":"string"}}},"schemas":{"CampaignRequestBody":{"title":"Campaign","required":["campaign"],"properties":{"campaign":{"required":["type","trigger","translations","activity","rules"],"properties":{"triggerStrategy":{"$ref":"#/components/schemas/TriggerStrategy"},"visibility":{"$ref":"#/components/schemas/Visibility"},"audience":{"$ref":"#/components/schemas/Audience"},"rules":{"$ref":"#/components/schemas/Rule"},"transactionItemsFilters":{"description":"Field that you can use to filter transaction items, which you can then use in the condition by providing the code, only allowed for transaction trigger","type":"array","items":{"$ref":"#/components/schemas/TransactionItemsFilters"}},"limits":{"$ref":"#/components/schemas/Limit"},"type":{"type":"string","enum":["direct","referral"]},"trigger":{"type":"string","enum":["transaction","return_transaction","custom_event","internal_event","time","achievement","custom_event_unique_code"]},"event":{"description":"Allowed only for campaign with trigger event","type":"string"},"activity":{"required":["startsAt"],"properties":{"startsAt":{"type":"string"},"endsAt":{"type":"string","nullable":true}},"type":"object"},"displayOrder":{"type":"number"},"active":{"type":"boolean"},"labels":{"type":"array","items":{"required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"}},"memberFilter":{"description":"Only allowed for time trigger","properties":{"strategy":{}},"type":"object"},"translations":{"$ref":"#/components/schemas/CampaignTranslations"},"customFields":{"type":"object","nullable":true,"description":"Custom-field values grouped by group key. PUT semantics: omitted or null → existing values kept (no-op); empty object {} → all values cleared (validation still runs); non-empty object → wholesale entity replace (every group not in the payload is also wiped). Requires the CUSTOM_FIELD_CAMPAIGN feature flag; when disabled the field is silently ignored. See the endpoint description for full semantics.","additionalProperties":{"type":"object","additionalProperties":true}}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"TriggerStrategy":{"properties":{"type":{"type":"string","enum":["birthday","registration_anniversary","daily","weekly","monthly"]},"executionSchedule":{"description":"Required for `weekly` and `monthly` type of campaign.","properties":{"dayOfWeek":{"description":"List of days when campaign should be executed. 0 for Sunday, 6 for Saturday.","type":"array","items":{"type":"integer","enum":[0,1,2,3,4,5,6]},"nullable":true},"dayOfMonth":{"description":"List of month days when campaign should be executed. 'L' for the last day of the month.","type":"array","items":{"oneOf":[{"type":"integer","enum":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]},{"type":"string","enum":["L"]}]},"nullable":true}},"type":"object","nullable":true}},"type":"object"},"Visibility":{"description":"Visibility settings for the campaign. Optional field.","properties":{"target":{"type":"string","enum":["segment","tier","none"]},"tiers":{"description":"Visibility settings for the campaign. Optional field.","type":"array","items":{"type":"string"}},"segments":{"description":"Visibility settings for the campaign. Optional field.","type":"array","items":{"type":"string"}}},"type":"object","additionalProperties":false},"Audience":{"description":"Audience settings for the campaign. Optional field.","properties":{"target":{"type":"string","enum":["segment","tier"]},"tiers":{"type":"array","items":{"type":"string"}},"segments":{"type":"array","items":{"type":"string"}}},"type":"object","nullable":true},"Rule":{"type":"array","items":{"required":["effects"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"target":{"description":"Selects which member the rule's effects apply to: `self` — the member whose event triggered the campaign (the referred member); `referrer` — the member who referred them.\n\nRequired on every rule of a `referral` campaign sent with `POST` or `PUT`: leaving it out is a `400` on `rules.N.target`. On a campaign of any other type the field is rejected outright. A `PATCH` that omits it keeps the stored value. `rules` is shared by every campaign type, so the schema cannot mark it required; the condition above is what decides.","type":"string","enum":["self","referrer"]},"lineTargets":{"description":"Accepted only when the campaign trigger is `transaction` or `return_transaction`.","type":"array","items":{"$ref":"#/components/schemas/LineTarget"}},"effects":{"type":"array","items":{"required":["effect"],"properties":{"effect":{"type":"string","enum":["give_points","give_reward","deduct_unit","assign_member_custom_attribute","remove_member_custom_attribute","grant_badge","cancel_transaction_effects","assign_member_to_tier"],"description":"`assign_member_to_tier` is accepted on five combinations of campaign `type` and `trigger`: `direct` × `custom_event`, `direct` × `challenge`, `referral` × `custom_event`, `direct` × `transaction` and `referral` × `transaction`. Every other combination is rejected with `400` on `rules.N.effects.M.effect` — `referral` × `challenge` among them, even though the challenge request body admits `type: referral`, and `return_transaction` on either type, even though it sits in the same trigger enum as `transaction`. This enum is shared by every request body that carries `rules`, so the value is advertised on campaign variants that cannot accept it — the list above, not the enum, is what decides. The effect puts the member on the configured tier and marks that tier as manually held on the member's tier progress, so it is not lost to an automatic downgrade; the member-history entry still reports `manually: false` and names the granting campaign instead.\n\nRepeating the trigger does not grant the tier twice. The grant is skipped when the member already holds the configured tier from an earlier grant or an administrator's assignment, and when the member holds a higher tier of the same set — the effect raises a member to the tier, never lowers them to it. It still runs for a member who reached the tier on their own: it reports `success`, appears in `effectsGiven`, and from then on the tier is protected from an automatic downgrade. A run whose only effect was skipped sends no `CampaignEffectWasApplied` webhook at all — not a webhook with an empty `effectsGiven`.\n\nA returned transaction does not take the tier back. `cancel_transaction_effects` reverses the points the original transaction earned and leaves the tier standing, along with the mark that protects it from an automatic downgrade. The return carries the `return_transaction` trigger, which no campaign holding this effect can match, so it neither revokes the grant nor makes a second one.\n\nOn a `referral` campaign the tier goes to the member named by the rule's `target`: `self` — the member whose event triggered the campaign, `referrer` — the member who referred them. A live run for a member who has no referrer is skipped whole — none of the campaign's effects run, not just this one. Simulation does not apply that skip; see `SimulateResult`.\n\nOn a multi-level referral campaign (`multiLevel` above 1) the campaign re-runs once for each member up the referrer chain, so a single event can grant the tier to as many members as `multiLevel` allows. The skip described above does not hold it to one: every run resolves `target` against a different member. The chain ends at the first member who has no referrer — that member's run is skipped whole, so they are not granted the tier.\n\nOn the `custom_event` trigger, `eventId` stays optional and guards only against the very same event being delivered twice. A different event — a second device registration, say — is a new event: the campaign runs again, and it is the tier grant that skips it, not the deduplication of the event. The `transaction` trigger carries no such guard: every transaction assigned to the member runs the campaign again, and the grant itself is the only thing that stops the second one from moving the member."},"pointsRule":{"description":"Only allowed for `give_points` and `deduct_unit` effect"},"walletCode":{"description":"Only allowed for `give_points` and `deduct_unit` effect","type":"string"},"relatedLineTarget":{"description":"Only allowed for `give_points` effect","type":"string","minLength":3,"maxLength":32},"transform":{"description":"Only allowed for `give_points` and `deduct_unit` effect","properties":{"tierMultiplier":{"description":"A tier without an entry uses 1.","required":["tierSetId"],"properties":{"tierSetId":{"type":"string","format":"uuid"},"tiers":{"type":"array","items":{"required":["tierId","factor"],"properties":{"tierId":{"type":"string","format":"uuid"},"factor":{"type":"number","minimum":0}},"type":"object","additionalProperties":false}}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"unitsLockRule":{"description":"The field allows you to set a custom pending for units given by campaign effects. Only allowed for `give_points` effect","required":["lockStrategy"],"properties":{"lockStrategy":{"type":"string","enum":["expression","from_wallet","no_pending"]},"expression":{"description":"This field is required for `lockStrategy = expression`","type":"string"}},"type":"object","additionalProperties":false},"unitsExpirationRule":{"description":"The field allows you to set a custom expiration for units given by campaign effects. Only allowed for `give_points` effect","required":["expirationStrategy"],"properties":{"expirationStrategy":{"type":"string","enum":["expression","from_wallet","never_expires"]},"expression":{"description":"This field is required for `lockStrategy = expression`","type":"string"}},"type":"object","additionalProperties":false},"rewardId":{"description":"Only allowed for `give_reward` effect","type":"string","format":"uuid"},"couponValueRule":{"description":"Only allowed for `give_reward` effect","type":"string"},"customAttributeKey":{"description":"Only allowed for `assign_member_custom_attribute` effect","type":"string"},"customAttributeValueRule":{"description":"Only allowed for `assign_member_custom_attribute` effect","type":"string"},"badgeSystemCode":{"description":"Only allowed for `grant_badge` effect","type":"string"},"tierSetId":{"description":"Only allowed for the `assign_member_to_tier` effect, and required for it. The tier set the configured tier belongs to.","type":"string","format":"uuid"},"tierId":{"description":"Only allowed for the `assign_member_to_tier` effect, and required for it. The tier the member is put on. It must belong to `tierSetId` and be an active tier of this store, otherwise the request is rejected with `400` on `rules.N.effects.M.tierId`.","type":"string","format":"uuid"}},"type":"object","additionalProperties":false}},"conditions":{"type":"array","items":{"oneOf":[{"title":"Condition","required":["operator","data"],"properties":{"attribute":{"type":"string"},"operator":{"type":"string","enum":["expression","is_equal","has_at_least_one_label","contains","not_contains","is_not_equal","is_not_one_of","is_one_of","matches_regex","is_greater","is_greater_or_equal","is_less","is_less_or_equal","ends_with","starts_with","is_after","is_before","is_between","is_day_of_week","is_month_of_year","is_not_between","is_day_of_month","is_time_between","is_one_of_group_values","is_not_one_of_group_values","not_contains_one_of","contains_one_of"]},"data":{}},"type":"object"},{"$ref":"#/components/schemas/NewCondition"}]}}},"type":"object"}},"LineTarget":{"required":["code"],"properties":{"code":{"type":"string","minLength":3,"maxLength":32},"name":{"type":"string","maxLength":32},"selector":{"description":"Send lines or sets, not both. An empty selector matches every line.","properties":{"lines":{"description":"Filters are AND-ed; an empty list matches every line.","properties":{"filters":{"type":"array","items":{"required":["value","condition"],"properties":{"value":{"required":["field"],"properties":{"field":{"type":"string","enum":["sku","name","qty","grossValue","category","maker","labels","catalogSku","catalogCategory","catalogBrand","catalogAttributes"]}},"type":"object","additionalProperties":false},"condition":{"$ref":"#/components/schemas/Condition"},"dataEnteredManually":{"type":"boolean"}},"type":"object","additionalProperties":false}}},"type":"object","additionalProperties":false},"sets":{"description":"Every part must be satisfied for one set to form.","type":"array","items":{"required":["requirements","filters"],"properties":{"requirements":{"required":["qtyPerSet"],"properties":{"qtyPerSet":{"type":"number","minimum":0.001,"maximum":100000000,"exclusiveMaximum":true}},"type":"object","additionalProperties":false},"filters":{"type":"array","minItems":1,"items":{"required":["value","condition"],"properties":{"value":{"required":["field"],"properties":{"field":{"type":"string","enum":["sku","name","qty","grossValue","category","maker","labels","catalogSku","catalogCategory","catalogBrand","catalogAttributes"]}},"type":"object","additionalProperties":false},"condition":{"$ref":"#/components/schemas/Condition"},"dataEnteredManually":{"type":"boolean"}},"type":"object","additionalProperties":false}}},"type":"object","additionalProperties":false}}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"Condition":{"required":["operator","value"],"properties":{"operator":{"type":"string","enum":["eq","neq","between","not_between","starts_with","ends_with","match","not_match","gt","gte","lt","lte","is_after","is_before","in","not_in","one_of","not_one_of","in_value_group","not_in_value_group","one_of_value_group","not_one_of_value_group"]},"value":{"oneOf":[{"description":"For operators `eq`, `neq`, `starts_with`, `ends_with`, `match`, `not_match` the value can be a string. For `match` and `not_match`, the string must be a valid regular expression.","type":"string"},{"description":"For operators `eq`, `neq`, `gt`, `gte`, `lt`, `lte` , the value can be a number.","type":"number"},{"description":"For operators `eq`, `neq`, the value can be a bool.","type":"boolean"},{"title":"datetime","description":"For operators `eq`, `neq` `is_after`, `is_before`, the value can be a datetime.","type":"string","format":"datetime","pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?Z$"},{"title":"array","type":"array","items":{"description":"For `in`, `not_in`, `one_of`, `not_one_of` operators, the values can be in array.","oneOf":[{"type":"number"},{"type":"string"},{"title":"custom attribute","properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"}]}},{"title":"between","description":"For `between`, `not_between` operators, the value is an object with 'from' and 'to'.","required":["from","to"],"properties":{"from":{"oneOf":[{"type":"number"},{"title":"datetime","type":"string","format":"datetime"}]},"to":{"oneOf":[{"type":"number"},{"title":"datetime","type":"string","format":"datetime"}]}},"type":"object"},{"title":"group of values","required":["groupValuesIds"],"properties":{"groupValuesIds":{"description":"For `in_value_group`, `not_in_value_group` operators, the value is an object with `groupValuesIds` array.","type":"array","items":{"type":"string","format":"uuid"}}},"type":"object"},{"title":"one of group of values","description":"For `one_of_value_group`, `not_one_of_value_group` operators, the value is an object with labelKey and `groupValuesIds` array.","required":["groupValuesIds","labelKey"],"properties":{"labelKey":{"type":"string"},"groupValuesIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"type":"object"}]}},"type":"object","additionalProperties":false},"NewCondition":{"title":"New condition","required":["value","condition"],"properties":{"value":{"required":["field"],"properties":{"field":{"type":"string","enum":["customer.email","customer.wallets","referrer.wallets","customer.badges","referrer.badges","transaction.items","challenge.trigger","challenge.completions","challenge.milestoneProgresses","lineTarget.count","lineTarget.qty","lineTarget.value"]},"params":{"description":"The `wallet` object applies only to the `customer.wallets` and `referrer.wallets` fields. The `walletTypeCode` field is used to precisely specify which wallet the condition should apply to. The `field` property defines which wallet field is used to retrieve the value for the condition.","type":"object","oneOf":[{"title":"wallet","required":["walletTypeCode","field"],"properties":{"walletTypeCode":{"type":"string"},"field":{"type":"string","enum":["activeUnits","spentUnits","earnedUnits","lockedUnits","blockUnits","expiredUnits"]}},"type":"object","additionalProperties":false},{"title":"badge","required":["badgeTypeId"],"properties":{"badgeTypeId":{"type":"string","format":"uuid"}},"type":"object","additionalProperties":false},{"title":"milestoneByRelationId","required":["milestoneRelationId"],"properties":{"milestoneRelationId":{"type":"string"}},"type":"object","additionalProperties":false},{"title":"milestoneById","required":["milestoneId"],"properties":{"milestoneId":{"type":"string","format":"uuid"}},"type":"object","additionalProperties":false},{"title":"lineTarget","required":["code"],"properties":{"code":{"type":"string","minLength":3,"maxLength":32}},"type":"object","additionalProperties":false}]},"filterCode":{"description":"In this field you can specify which transaction items filters you want to use in condition","type":"string"},"aggregation":{"description":"Available only for transaction.items","required":["type"],"properties":{"type":{"type":"string","enum":["sum","count"]},"field":{"type":"string"}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"condition":{"$ref":"#/components/schemas/Condition"}},"type":"object"},"TransactionItemsFilters":{"required":["code"],"properties":{"code":{"type":"string"},"name":{"type":"string"},"filters":{"type":"array","items":{"required":["value","condition"],"properties":{"value":{"required":["field"],"properties":{"field":{"type":"string","enum":["sku","name","qty","grossValue","category","maker","labels","catalogSku","catalogCategory","catalogBrand","catalogAttributes"]}},"type":"object","additionalProperties":false},"condition":{"$ref":"#/components/schemas/Condition"},"dataEnteredManually":{"type":"boolean"}},"type":"object","additionalProperties":false}}},"type":"object","additionalProperties":false},"Limit":{"properties":{"points":{"required":["value"],"properties":{"interval":{"properties":{"type":{"type":"string"},"value":{"type":"integer","deprecated":true}},"type":"object"},"value":{"type":"number","format":"float"}},"type":"object"},"pointsPerMember":{"required":["value"],"properties":{"interval":{"properties":{"type":{"type":"string"},"value":{"type":"integer","deprecated":true}},"type":"object"},"value":{"type":"number","format":"float"}},"type":"object"},"executionsPerMember":{"required":["value"],"properties":{"interval":{"properties":{"type":{"type":"string"},"value":{"type":"integer","deprecated":true}},"type":"object"},"value":{"type":"number","format":"float"}},"type":"object"}},"type":"object"},"CampaignTranslations":{"description":"This field is used to save the name and description in the language of your choice","required":["en"],"properties":{"en":{"required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}},"type":"object"},"pl":{"required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}},"type":"object"}},"type":"object"},"AchievementCampaignRequestBody":{"title":"AchievementCampaign","required":["campaign"],"properties":{"campaign":{"required":["type","trigger","translations","activity","rules","achievementId"],"properties":{"triggerStrategy":{"$ref":"#/components/schemas/TriggerStrategy"},"visibility":{"$ref":"#/components/schemas/Visibility"},"audience":{"$ref":"#/components/schemas/Audience"},"rules":{"$ref":"#/components/schemas/Rule"},"limits":{"$ref":"#/components/schemas/Limit"},"type":{"type":"string","enum":["direct","referral"]},"trigger":{"type":"string"},"activity":{"required":["startsAt"],"properties":{"startsAt":{"type":"string"},"endsAt":{"type":"string","nullable":true}},"type":"object"},"displayOrder":{"type":"number"},"active":{"type":"boolean"},"labels":{"type":"array","items":{"required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"}},"translations":{"$ref":"#/components/schemas/CampaignTranslations"},"achievementId":{"type":"string","format":"uuid","deprecated":true},"customFields":{"type":"object","nullable":true,"description":"Custom-field values grouped by group key. PUT semantics: omitted or null → existing values kept (no-op); empty object {} → all values cleared (validation still runs); non-empty object → wholesale entity replace (every group not in the payload is also wiped). Requires the CUSTOM_FIELD_CAMPAIGN feature flag; when disabled the field is silently ignored. See the endpoint description for full semantics.","additionalProperties":{"type":"object","additionalProperties":true}}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"UniqueCodeCampaignRequestBody":{"title":"RedemptionCampaign","required":["campaign"],"properties":{"campaign":{"description":"Campaign details combining common fields with specific strategy requirements.","type":"object","allOf":[{"required":["type","trigger","translations","activity","eventCodeAttribute","rules","event"],"properties":{"type":{"type":"string"},"trigger":{"type":"string"},"activity":{"required":["startsAt"],"properties":{"startsAt":{"type":"string"},"endsAt":{"type":"string","nullable":true}},"type":"object"},"displayOrder":{"type":"number"},"active":{"type":"boolean"},"labels":{"type":"array","items":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"}},"translations":{"$ref":"#/components/schemas/CampaignTranslations"},"rules":{"$ref":"#/components/schemas/Rule"},"limits":{"$ref":"#/components/schemas/Limit"},"visibility":{"$ref":"#/components/schemas/Visibility"},"audience":{"$ref":"#/components/schemas/Audience"},"event":{"type":"string"},"eventCodeAttribute":{"type":"string"},"customFields":{"type":"object","nullable":true,"description":"Custom-field values grouped by group key. POST-only schema (unique-code campaign creation): omitted, null, or empty {} → no values written; non-empty → persisted on the new campaign. Required-field validation always runs (enforceRequired). Requires the CUSTOM_FIELD_CAMPAIGN feature flag; when disabled the field is silently ignored.","additionalProperties":{"type":"object","additionalProperties":true}}},"type":"object"},{"oneOf":[{"title":"Internal Generator (Default)","required":["generateCodes","codeGenerator"],"properties":{"isExternalCodeSource":{"description":"Defaults to false. If false or omitted, generator fields are required.","type":"boolean"},"generateCodes":{"type":"integer"},"codeGenerator":{"required":["characterSet","length"],"properties":{"characterSet":{"type":"string"},"length":{"type":"integer"},"prefix":{"type":"string"}},"type":"object","additionalProperties":false}},"type":"object"},{"title":"External Source (Import)","required":["isExternalCodeSource"],"properties":{"isExternalCodeSource":{"description":"Set to true to skip code generation and import codes manually.","type":"boolean","enum":[true]}},"type":"object"}]}]}},"type":"object","additionalProperties":false},"MultiReferralCampaignRequestBody":{"title":"MultiReferralCampaign","description":"When campaign is referral type, you can specify multi level","required":["campaign"],"properties":{"campaign":{"required":["multiLevel","type","trigger","translations","activity","rules"],"properties":{"triggerStrategy":{"$ref":"#/components/schemas/TriggerStrategy"},"visibility":{"$ref":"#/components/schemas/Visibility"},"audience":{"$ref":"#/components/schemas/Audience"},"rules":{"$ref":"#/components/schemas/Rule"},"transactionItemsFilters":{"description":"Field that you can use to filter transaction items, which you can then use in the condition by providing the code, only allowed for transaction trigger","type":"array","items":{"$ref":"#/components/schemas/TransactionItemsFilters"}},"limits":{"$ref":"#/components/schemas/Limit"},"type":{"type":"string","enum":["direct","referral"]},"multiLevel":{"description":"How many members up the referrer chain one event runs the campaign for. Each level is a separate run for a different member, and every effect in `rules` is applied once per run — so a value above 1 multiplies the effects a single event produces. The chain ends early at the first member who has no referrer.","type":"number"},"trigger":{"type":"string","enum":["transaction","return_transaction","custom_event","internal_event","time","achievement","custom_event_unique_code"]},"event":{"type":"string"},"activity":{"required":["startsAt"],"properties":{"startsAt":{"type":"string"},"endsAt":{"type":"string","nullable":true}},"type":"object"},"displayOrder":{"type":"number"},"active":{"type":"boolean"},"labels":{"type":"array","items":{"required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"}},"memberFilter":{"description":"Only allowed for time trigger","properties":{"strategy":{}},"type":"object"},"translations":{"$ref":"#/components/schemas/CampaignTranslations"},"customFields":{"type":"object","nullable":true,"description":"Custom-field values grouped by group key. PUT semantics: omitted or null → existing values kept (no-op); empty object {} → all values cleared (validation still runs); non-empty object → wholesale entity replace (every group not in the payload is also wiped). Requires the CUSTOM_FIELD_CAMPAIGN feature flag; when disabled the field is silently ignored. See the endpoint description for full semantics.","additionalProperties":{"type":"object","additionalProperties":true}}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"LeaderboardCampaignRequestBody":{"title":"LeaderboardCampaign","required":["campaign"],"properties":{"campaign":{"required":["type","trigger","translations","activity","leaderboard"],"properties":{"triggerStrategy":{"$ref":"#/components/schemas/TriggerStrategy"},"visibility":{"$ref":"#/components/schemas/Visibility"},"audience":{"$ref":"#/components/schemas/Audience"},"rules":{"$ref":"#/components/schemas/Rule"},"type":{"type":"string","enum":["direct","referral"]},"trigger":{"type":"string"},"activity":{"required":["startsAt"],"properties":{"startsAt":{"type":"string"},"endsAt":{"type":"string","nullable":true}},"type":"object"},"displayOrder":{"type":"number"},"active":{"type":"boolean"},"labels":{"type":"array","items":{"required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"}},"translations":{"$ref":"#/components/schemas/CampaignTranslations"},"leaderboard":{"$ref":"#/components/schemas/Leaderboard"},"customFields":{"type":"object","nullable":true,"description":"Custom-field values grouped by group key. PUT semantics: omitted or null → existing values kept (no-op); empty object {} → all values cleared (validation still runs); non-empty object → wholesale entity replace (every group not in the payload is also wiped). Requires the CUSTOM_FIELD_CAMPAIGN feature flag; when disabled the field is silently ignored. See the endpoint description for full semantics.","additionalProperties":{"type":"object","additionalProperties":true}}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"Leaderboard":{"properties":{"metric":{"required":["type","walletTypeCode"],"properties":{"type":{"type":"string","enum":["earned_units_cumulative"]},"walletTypeCode":{"type":"string"}},"type":"object"},"cycles":{"description":"Optional cycle definition. Without `cycles` the leaderboard is timeless (a single open-ended iteration). Only one cycle is supported.\n","type":"array","maxItems":1,"items":{"required":["type"],"properties":{"type":{"type":"string","enum":["end_of_the_month"]},"code":{"description":"Caller-defined cycle code returned alongside leaderboard rankings. Optional — when omitted the server applies a default code.\n","type":"string"}},"type":"object"}},"groupingField":{"description":"Splits the leaderboard into sub-rankings per distinct group value. Members without a resolvable group value are excluded from the grouped leaderboard. The grouping configuration is set at campaign creation and is read-only afterwards. Submitting a `groupingField` on update (PUT) that differs from the stored one — including adding or removing it — is rejected with HTTP 400 to keep historical iterations consistent. An identical `groupingField` (or none) is accepted.\n","required":["type","key"],"properties":{"type":{"type":"string","description":"`address_field` groups by an address sub-field on the member profile; `custom_attribute` groups by a member custom attribute key.\n","enum":["address_field","custom_attribute"]},"key":{"type":"string","description":"For `address_field`, one of: `city`, `country`, `province`, `postal`. For `custom_attribute`, the custom attribute key on the member profile.\n"}},"type":"object"}},"type":"object"},"ChallengeCampaignRequestBody":{"title":"ChallengeCampaign","required":["campaign"],"properties":{"campaign":{"required":["type","trigger","translations","activity","rules","milestones"],"properties":{"triggerStrategy":{"$ref":"#/components/schemas/TriggerStrategy"},"visibility":{"$ref":"#/components/schemas/Visibility"},"audience":{"$ref":"#/components/schemas/Audience"},"rules":{"$ref":"#/components/schemas/Rule"},"limits":{"$ref":"#/components/schemas/Limit"},"type":{"type":"string","enum":["direct","referral"]},"trigger":{"type":"string"},"activity":{"required":["startsAt"],"properties":{"startsAt":{"type":"string"},"endsAt":{"type":"string","nullable":true}},"type":"object"},"displayOrder":{"type":"number"},"active":{"type":"boolean"},"labels":{"type":"array","items":{"required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"}},"translations":{"$ref":"#/components/schemas/CampaignTranslations"},"challengeLimit":{"$ref":"#/components/schemas/ChallengeLimit"},"challengeAvailability":{"$ref":"#/components/schemas/AchievementActivity"},"milestones":{"type":"array","items":{"$ref":"#/components/schemas/Milestone"}},"customFields":{"type":"object","nullable":true,"description":"Custom-field values grouped by group key. PUT semantics: omitted or null → existing values kept (no-op); empty object {} → all values cleared (validation still runs); non-empty object → wholesale entity replace (every group not in the payload is also wiped). Requires the CUSTOM_FIELD_CAMPAIGN feature flag; when disabled the field is silently ignored. See the endpoint description for full semantics.","additionalProperties":{"type":"object","additionalProperties":true}}},"type":"object","additionalProperties":false}},"type":"object","additionalProperties":false},"ChallengeLimit":{"properties":{"interval":{"$ref":"#/components/schemas/LimitInterval"},"value":{"type":"integer"}},"type":"object"},"LimitInterval":{"properties":{"type":{"type":"string"},"value":{"type":"integer"}},"type":"object"},"AchievementActivity":{"properties":{"data":{"oneOf":[{"type":"string"},{"properties":{"from":{"type":"string"},"to":{"type":"string"}},"type":"object"},{"type":"array","items":{"type":"string"}}]},"operator":{"type":"string"}},"type":"object"},"Milestone":{"properties":{"translations":{"properties":{"en":{"properties":{"name":{"type":"string"},"description":{"type":"string"}},"type":"object"}},"type":"object"},"milestoneId":{"type":"string"},"completeRule":{"$ref":"#/components/schemas/CompleteRule"},"aggregation":{"$ref":"#/components/schemas/Aggregation"},"uniqueReferee":{"type":"boolean"},"event":{"type":"string"},"trigger":{"type":"string"},"type":{"type":"string"},"conditions":{"type":"array","items":{"type":"object"}},"limit":{"$ref":"#/components/schemas/ChallengeLimit"}},"type":"object"},"CompleteRule":{"properties":{"periodGoal":{"oneOf":[{"type":"string"},{"type":"number"}]},"period":{"$ref":"#/components/schemas/Period"},"uniqueAttribute":{"type":"string"}},"type":"object"},"Period":{"properties":{"type":{"type":"string"},"consecutive":{"type":"integer"},"value":{"type":"integer"}},"type":"object"},"Aggregation":{"properties":{"type":{"type":"string"},"rule":{"type":"string"}},"type":"object"},"ExpiredToken":{"required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}},"type":"object"},"InvalidToken":{"required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}},"type":"object"},"Unauthorized":{"required":["code","message"],"properties":{"code":{"type":"integer"},"message":{"type":"string"}},"type":"object"}},"responses":{"BadRequest":{"description":"Bad request.","content":{"application/json":{"schema":{"required":["code","message","errors"],"properties":{"code":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"required":["message","parameters","plural","code","path"],"properties":{"message":{"type":"string"},"parameters":{},"plural":{"type":"integer","nullable":true},"code":{"type":"string"},"path":{"type":"string"}},"type":"object"}}},"type":"object"}}}},"AccessDenied":{"description":"Forbidden.","content":{"application/json":{"schema":{"required":["code","message"],"properties":{"code":{"type":"integer"},"message":{"type":"string"}},"type":"object"}}}},"NotFound":{"description":"Not found.","content":{"application/json":{"schema":{"required":["code","message"],"properties":{"code":{"type":"integer"},"message":{"type":"string"}},"type":"object"}}}}}},"paths":{"/api/{storeCode}/campaign":{"post":{"tags":["Campaign"],"summary":"Add a new campaign","description":"<label style=\"background-color: #D4EDBC;padding:5px;\">Management</label><br><br>\nThis method allows creating a new Campaign.<br><br>\n<strong>Custom-fields semantics on POST:</strong> <ul>\n  <li><code>customFields</code> omitted, <code>null</code>, or <code>{}</code> →\n    the campaign is created with no custom-field values; required-field validation\n    still runs and the request fails with 400 if any active campaign custom-field\n    group contains a required field.</li>\n  <li><code>customFields: { groupKey: { fieldKey: value, ... }, ... }</code> →\n    the provided values are persisted on the new campaign; required-field validation\n    runs against the payload.</li>\n</ul> The feature flag <code>CUSTOM_FIELD_CAMPAIGN</code> must be enabled; when disabled the <code>customFields</code> key is silently ignored.\n","operationId":"_campaignPost","parameters":[{"$ref":"#/components/parameters/storeCode"}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CampaignRequestBody"},{"$ref":"#/components/schemas/AchievementCampaignRequestBody"},{"$ref":"#/components/schemas/UniqueCodeCampaignRequestBody"},{"$ref":"#/components/schemas/MultiReferralCampaignRequestBody"},{"$ref":"#/components/schemas/LeaderboardCampaignRequestBody"},{"$ref":"#/components/schemas/ChallengeCampaignRequestBody"}]}}}},"responses":{"200":{"description":"Return created campaign ID.","content":{"application/json":{"schema":{"required":["campaignId"],"properties":{"campaignId":{"type":"string","format":"uuid"}},"type":"object","additionalProperties":false}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ExpiredToken"},{"$ref":"#/components/schemas/InvalidToken"},{"$ref":"#/components/schemas/Unauthorized"}]}}}},"403":{"$ref":"#/components/responses/AccessDenied"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
````


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.openloyalty.io/api-reference/campaign/add-a-new-campaign.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
