diff --git a/.changeset/targeting-client-campaign-schedule.md b/.changeset/targeting-client-campaign-schedule.md new file mode 100644 index 00000000..d34f70d1 --- /dev/null +++ b/.changeset/targeting-client-campaign-schedule.md @@ -0,0 +1,5 @@ +--- +"@epilot/targeting-client": minor +--- + +Regenerate types from the Targeting API for campaign scheduling (ER-5517): `CampaignStatus` gets `scheduled` (launched with a future `start_date`, started on its own at that time), the campaign's `start_date`/`end_date` become date-times, and `changeCampaignStatus` documents the schedule/cancel transitions and the `INVALID_CAMPAIGN_DATES`, `CAMPAIGN_END_BEFORE_START` and `CAMPAIGN_END_IN_PAST` errors. `setupCampaign` accepts an optional `campaign.start_date` and `end_date`. Resetting a stopped campaign clears its dates, and launching without a target or delivery method is documented as `409`. Also syncs the `entity_ui_status` recipient filter, the `403` responses of `changeCampaignStatus` and `setupCampaign`, and the updated target `search` and `sort` descriptions. diff --git a/clients/targeting-client/src/openapi-runtime.json b/clients/targeting-client/src/openapi-runtime.json index 4243eaab..85ceb8d9 100644 --- a/clients/targeting-client/src/openapi-runtime.json +++ b/clients/targeting-client/src/openapi-runtime.json @@ -243,6 +243,10 @@ { "name": "email_status", "in": "query" + }, + { + "name": "entity_ui_status", + "in": "query" } ], "responses": {} diff --git a/clients/targeting-client/src/openapi.d.ts b/clients/targeting-client/src/openapi.d.ts index 2420e16b..e833403b 100644 --- a/clients/targeting-client/src/openapi.d.ts +++ b/clients/targeting-client/src/openapi.d.ts @@ -320,14 +320,47 @@ declare namespace Components { _acl?: /* Access control list (ACL) for an entity. Defines sharing access to external orgs or users. */ BaseEntityAcl; name?: string; goal?: string; - status?: CampaignStatus; - start_date?: string; // date - end_date?: string; // date + status?: /** + * Lifecycle status of a campaign. + * + * - `draft`: not launched yet. + * - `scheduled`: launched with a `start_date` still in the future. It collects no recipients and + * appears through no delivery method until it starts on its own at `start_date`. + * - `activating`: launching; recipients are being collected. + * - `active`: running. + * - `inactive`: stopped, by hand or on its own at `end_date`. + * + */ + CampaignStatus; + /** + * When the campaign starts. Optional: if set to a future time when the campaign is launched, + * the campaign is `scheduled` and starts on its own at this time. Otherwise it is set to the + * time the campaign is launched. + * + */ + start_date?: string; // date-time + /** + * When the campaign ends. Optional: if set, the running campaign stops on its own at this + * time. Otherwise it is set to the time the campaign is stopped by hand. + * + */ + end_date?: string; // date-time flow_id?: string; job_id?: string; target?: BaseRelation; } - export type CampaignStatus = "draft" | "activating" | "active" | "inactive"; + /** + * Lifecycle status of a campaign. + * + * - `draft`: not launched yet. + * - `scheduled`: launched with a `start_date` still in the future. It collects no recipients and + * appears through no delivery method until it starts on its own at `start_date`. + * - `activating`: launching; recipients are being collected. + * - `active`: running. + * - `inactive`: stopped, by hand or on its own at `end_date`. + * + */ + export type CampaignStatus = "draft" | "scheduled" | "activating" | "active" | "inactive"; /** * Describes the structure of a client error response, which can be one of several types: * 1. `MessageError`: Contains a 'message' field for general descriptive errors. @@ -1823,6 +1856,18 @@ declare namespace Components { * b8c01433-5556-4e2b-aad4-6f5348d1df84 */ BaseUUID /* uuid */[]; + /** + * Optional start of the campaign. Launching the campaign before this time schedules it, and + * it starts on its own at this time. Without it, the campaign starts when it is launched. + * + */ + start_date?: string; // date-time + /** + * Optional end of the campaign. Must be after `start_date` and in the future. The campaign + * stops on its own at this time. Without it, the campaign runs until it is stopped. + * + */ + end_date?: string; // date-time }; /** * Optional journey configuration selected in the wizard. Only sent by the @@ -1965,7 +2010,7 @@ declare namespace Components { }; /** * Free text search entered in the target builder. - * Not applied when resolving the target, e.g. by `getTargetQueries` or `matchTargets`. + * Applied when resolving the target like the search of entity views: matched against all fields and combined with `filter` using AND. * */ search?: string; @@ -2002,7 +2047,8 @@ declare namespace Components { error?: string; /** * Elasticsearch sort fields for the target's sort order, ready to be passed to entity search. - * Ends with an `_id` tie-breaker so the order is stable. Omitted when the target has no sort. + * Ends with an `_id` tie-breaker so the order is stable. A target with a limit but no sort returns + * `_created_at:desc` and `_id:desc` (newest first). Omitted when the target has neither. * * example: * [ @@ -2070,6 +2116,8 @@ declare namespace Paths { namespace Responses { export type $200 = Components.Responses.CampaignResponse; export type $400 = Components.Responses.ClientErrorResponse; + export type $403 = Components.Responses.ClientErrorResponse; + export type $409 = Components.Responses.ClientErrorResponse; export type $500 = Components.Responses.ServerErrorResponse; } } @@ -2167,6 +2215,13 @@ declare namespace Paths { * */ Components.Schemas.EmailStatus; + export type EntityUiStatus = /** + * Lifecycle status of a Next Best Action on the Entity-UI channel. Unlike the portal + * channel there is no `sent` state: an NBA recipient is born at `seen`, the moment the + * action is first rendered to an agent. + * + */ + Components.Schemas.EntityUiStatus; export type Limit = number; export type Next = string; export type PortalStatus = Components.Schemas.PortalStatus; @@ -2182,6 +2237,7 @@ declare namespace Paths { automation_status?: Parameters.AutomationStatus; portal_status?: Parameters.PortalStatus; email_status?: Parameters.EmailStatus; + entity_ui_status?: Parameters.EntityUiStatus; } namespace Responses { export type $200 = Components.Responses.RecipientsResponse; @@ -2266,6 +2322,7 @@ declare namespace Paths { namespace Responses { export type $201 = Components.Responses.SetupCampaignResponse; export type $400 = Components.Responses.ClientErrorResponse; + export type $403 = Components.Responses.ClientErrorResponse; export type $500 = Components.Responses.ServerErrorResponse; export type $504 = Components.Responses.ServerErrorResponse; } @@ -2353,9 +2410,20 @@ export interface OperationMethods { /** * changeCampaignStatus - changeCampaignStatus * - * Change the status of a campaign to a desired status. + * Moves a campaign to its next status, depending on its current one: + * + * - `draft`: launches the campaign. With a `start_date` still in the future it becomes `scheduled` and + * starts on its own at that time; otherwise it starts now (`activating`, then `active`). Rejected with + * 400 if the dates are invalid: `INVALID_CAMPAIGN_DATES` (unparsable), `CAMPAIGN_END_BEFORE_START` + * or `CAMPAIGN_END_IN_PAST`. + * - `scheduled`: cancels the schedule; the campaign goes back to `draft` and keeps its dates. + * - `active`: stops the campaign (`inactive`) and sets `end_date` to now. + * - `inactive`: resets the campaign to `draft` and clears its `start_date` and `end_date`: they + * recorded the previous run, and a past end date would block launching it again. * - * The status can be one of the following: active, inactive. + * Only launching needs a target and a delivery method (an automation flow, a portal block or a valid + * Next Best Action); otherwise it is rejected with 409 `CAMPAIGN_HAS_NO_TARGET` or + * `CAMPAIGN_HAS_NO_DELIVERY_METHOD`. Cancelling, stopping and resetting work without them. * * Status transition is accompanied by side effects, e.g., automation execution. * @@ -2397,6 +2465,9 @@ export interface OperationMethods { * (success, pending, in_progress, cancelled) will be skipped to prevent * accidentally retriggering successful or ongoing automations. * + * A campaign that has ended (at its `end_date`, or stopped by hand) starts no new + * automation runs: the request is rejected with 400 and message `Campaign has ended`. + * */ 'retriggerCampaignAutomations'( parameters?: Parameters | null, @@ -2409,6 +2480,11 @@ export interface OperationMethods { * Creates a `campaign` entity together with its related entities and configurations in a single call. * Used by the campaign wizard UI, but not restricted to it. * + * The campaign is created as a `draft`. Its optional `start_date` and `end_date` take effect when it is + * launched (see `changeCampaignStatus`). Returns 400 with `INVALID_CAMPAIGN_DATES`, + * `CAMPAIGN_END_BEFORE_START` or `CAMPAIGN_END_IN_PAST` when the dates could not be launched, and + * nothing is created. + * */ 'setupCampaign'( parameters?: Parameters | null, @@ -2587,9 +2663,20 @@ export interface PathsDictionary { /** * changeCampaignStatus - changeCampaignStatus * - * Change the status of a campaign to a desired status. + * Moves a campaign to its next status, depending on its current one: * - * The status can be one of the following: active, inactive. + * - `draft`: launches the campaign. With a `start_date` still in the future it becomes `scheduled` and + * starts on its own at that time; otherwise it starts now (`activating`, then `active`). Rejected with + * 400 if the dates are invalid: `INVALID_CAMPAIGN_DATES` (unparsable), `CAMPAIGN_END_BEFORE_START` + * or `CAMPAIGN_END_IN_PAST`. + * - `scheduled`: cancels the schedule; the campaign goes back to `draft` and keeps its dates. + * - `active`: stops the campaign (`inactive`) and sets `end_date` to now. + * - `inactive`: resets the campaign to `draft` and clears its `start_date` and `end_date`: they + * recorded the previous run, and a past end date would block launching it again. + * + * Only launching needs a target and a delivery method (an automation flow, a portal block or a valid + * Next Best Action); otherwise it is rejected with 409 `CAMPAIGN_HAS_NO_TARGET` or + * `CAMPAIGN_HAS_NO_DELIVERY_METHOD`. Cancelling, stopping and resetting work without them. * * Status transition is accompanied by side effects, e.g., automation execution. * @@ -2637,6 +2724,9 @@ export interface PathsDictionary { * (success, pending, in_progress, cancelled) will be skipped to prevent * accidentally retriggering successful or ongoing automations. * + * A campaign that has ended (at its `end_date`, or stopped by hand) starts no new + * automation runs: the request is rejected with 400 and message `Campaign has ended`. + * */ 'post'( parameters?: Parameters | null, @@ -2651,6 +2741,11 @@ export interface PathsDictionary { * Creates a `campaign` entity together with its related entities and configurations in a single call. * Used by the campaign wizard UI, but not restricted to it. * + * The campaign is created as a `draft`. Its optional `start_date` and `end_date` take effect when it is + * launched (see `changeCampaignStatus`). Returns 400 with `INVALID_CAMPAIGN_DATES`, + * `CAMPAIGN_END_BEFORE_START` or `CAMPAIGN_END_IN_PAST` when the dates could not be launched, and + * nothing is created. + * */ 'post'( parameters?: Parameters | null, diff --git a/clients/targeting-client/src/openapi.json b/clients/targeting-client/src/openapi.json index 9adf4f99..640b90e3 100644 --- a/clients/targeting-client/src/openapi.json +++ b/clients/targeting-client/src/openapi.json @@ -38,7 +38,7 @@ "post": { "operationId": "changeCampaignStatus", "summary": "changeCampaignStatus", - "description": "Change the status of a campaign to a desired status.\n\nThe status can be one of the following: active, inactive.\n\nStatus transition is accompanied by side effects, e.g., automation execution.\n", + "description": "Moves a campaign to its next status, depending on its current one:\n\n- `draft`: launches the campaign. With a `start_date` still in the future it becomes `scheduled` and\n starts on its own at that time; otherwise it starts now (`activating`, then `active`). Rejected with\n 400 if the dates are invalid: `INVALID_CAMPAIGN_DATES` (unparsable), `CAMPAIGN_END_BEFORE_START`\n or `CAMPAIGN_END_IN_PAST`.\n- `scheduled`: cancels the schedule; the campaign goes back to `draft` and keeps its dates.\n- `active`: stops the campaign (`inactive`) and sets `end_date` to now.\n- `inactive`: resets the campaign to `draft` and clears its `start_date` and `end_date`: they\n recorded the previous run, and a past end date would block launching it again.\n\nOnly launching needs a target and a delivery method (an automation flow, a portal block or a valid\nNext Best Action); otherwise it is rejected with 409 `CAMPAIGN_HAS_NO_TARGET` or\n`CAMPAIGN_HAS_NO_DELIVERY_METHOD`. Cancelling, stopping and resetting work without them.\n\nStatus transition is accompanied by side effects, e.g., automation execution.\n", "tags": [ "Campaign" ], @@ -59,6 +59,12 @@ "400": { "$ref": "#/components/responses/ClientErrorResponse" }, + "403": { + "$ref": "#/components/responses/ClientErrorResponse" + }, + "409": { + "$ref": "#/components/responses/ClientErrorResponse" + }, "500": { "$ref": "#/components/responses/ServerErrorResponse" } @@ -131,7 +137,7 @@ "post": { "operationId": "retriggerCampaignAutomations", "summary": "retriggerCampaignAutomations", - "description": "Retrigger automation executions for specific campaign recipients that have failed.\n\nThis endpoint starts new automation executions for the specified recipients\nusing the campaign's associated automation flow. Only recipients with\nautomation_status 'failed' will be processed. Recipients with other statuses\n(success, pending, in_progress, cancelled) will be skipped to prevent\naccidentally retriggering successful or ongoing automations.\n", + "description": "Retrigger automation executions for specific campaign recipients that have failed.\n\nThis endpoint starts new automation executions for the specified recipients\nusing the campaign's associated automation flow. Only recipients with\nautomation_status 'failed' will be processed. Recipients with other statuses\n(success, pending, in_progress, cancelled) will be skipped to prevent\naccidentally retriggering successful or ongoing automations.\n\nA campaign that has ended (at its `end_date`, or stopped by hand) starts no new\nautomation runs: the request is rejected with 400 and message `Campaign has ended`.\n", "tags": [ "Campaign Delivery" ], @@ -175,7 +181,7 @@ "post": { "operationId": "setupCampaign", "summary": "setupCampaign", - "description": "Creates a `campaign` entity together with its related entities and configurations in a single call.\nUsed by the campaign wizard UI, but not restricted to it.\n", + "description": "Creates a `campaign` entity together with its related entities and configurations in a single call.\nUsed by the campaign wizard UI, but not restricted to it.\n\nThe campaign is created as a `draft`. Its optional `start_date` and `end_date` take effect when it is\nlaunched (see `changeCampaignStatus`). Returns 400 with `INVALID_CAMPAIGN_DATES`,\n`CAMPAIGN_END_BEFORE_START` or `CAMPAIGN_END_IN_PAST` when the dates could not be launched, and\nnothing is created.\n", "tags": [ "Campaign" ], @@ -201,6 +207,9 @@ "400": { "$ref": "#/components/responses/ClientErrorResponse" }, + "403": { + "$ref": "#/components/responses/ClientErrorResponse" + }, "500": { "$ref": "#/components/responses/ServerErrorResponse" }, @@ -646,6 +655,14 @@ "schema": { "$ref": "#/components/schemas/EmailStatus" } + }, + { + "name": "entity_ui_status", + "in": "query", + "description": "Filter by Entity UI (Next Best Action) status", + "schema": { + "$ref": "#/components/schemas/EntityUiStatus" + } } ], "responses": { @@ -936,9 +953,11 @@ }, "CampaignStatus": { "type": "string", + "description": "Lifecycle status of a campaign.\n\n- `draft`: not launched yet.\n- `scheduled`: launched with a `start_date` still in the future. It collects no recipients and\n appears through no delivery method until it starts on its own at `start_date`.\n- `activating`: launching; recipients are being collected.\n- `active`: running.\n- `inactive`: stopped, by hand or on its own at `end_date`.\n", "default": "draft", "enum": [ "draft", + "scheduled", "activating", "active", "inactive" @@ -997,11 +1016,13 @@ }, "start_date": { "type": "string", - "format": "date" + "format": "date-time", + "description": "When the campaign starts. Optional: if set to a future time when the campaign is launched,\nthe campaign is `scheduled` and starts on its own at this time. Otherwise it is set to the\ntime the campaign is launched.\n" }, "end_date": { "type": "string", - "format": "date" + "format": "date-time", + "description": "When the campaign ends. Optional: if set, the running campaign stops on its own at this\ntime. Otherwise it is set to the time the campaign is stopped by hand.\n" }, "flow_id": { "type": "string" @@ -1051,7 +1072,7 @@ }, "search": { "type": "string", - "description": "Free text search entered in the target builder.\nNot applied when resolving the target, e.g. by `getTargetQueries` or `matchTargets`.\n" + "description": "Free text search entered in the target builder.\nApplied when resolving the target like the search of entity views: matched against all fields and combined with `filter` using AND.\n" }, "sort": { "type": "array", @@ -1358,7 +1379,7 @@ }, "sort": { "type": "array", - "description": "Elasticsearch sort fields for the target's sort order, ready to be passed to entity search.\nEnds with an `_id` tie-breaker so the order is stable. Omitted when the target has no sort.\n", + "description": "Elasticsearch sort fields for the target's sort order, ready to be passed to entity search.\nEnds with an `_id` tie-breaker so the order is stable. A target with a limit but no sort returns\n`_created_at:desc` and `_id:desc` (newest first). Omitted when the target has neither.\n", "items": { "type": "string" }, @@ -1837,6 +1858,16 @@ "items": { "$ref": "#/components/schemas/BaseUUID" } + }, + "start_date": { + "type": "string", + "format": "date-time", + "description": "Optional start of the campaign. Launching the campaign before this time schedules it, and\nit starts on its own at this time. Without it, the campaign starts when it is launched.\n" + }, + "end_date": { + "type": "string", + "format": "date-time", + "description": "Optional end of the campaign. Must be after `start_date` and in the future. The campaign\nstops on its own at this time. Without it, the campaign runs until it is stopped.\n" } }, "required": [