From b39cce702c9b4ae9ff04011530f9f9fd16e793b3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 19:48:16 +0000 Subject: [PATCH 1/2] feat: Remove /bulk endpoints from api-spec (C-19507) (#171) * Remove /bulk endpoints from api-spec (C-19507) Removes the `/bulk` resource and all of its endpoints: - POST /bulk (create job) - POST /bulk/{job_id} (add users) - GET /bulk/{job_id} (get job) - POST /bulk/{job_id}/run (run job) - GET /bulk/{job_id}/users (get users) Deletes the corresponding paths and now-orphaned Bulk component schemas from specs/openapi.yml and the `bulk` resource from specs/stainless.yml. The unrelated /users/{user_id}/preferences bulk update/replace endpoints are untouched. Co-Authored-By: Claude Opus 4.8 * Remove bulk e2e test The /bulk endpoints were removed, so the generated SDK no longer exposes courier.bulk. Delete the corresponding e2e test. Co-Authored-By: Claude Opus 4.8 * Remove bulk SDK examples The /bulk endpoints were removed, so the generated SDKs no longer expose the bulk resource. Delete the per-language bulk example files (csharp, go, java, kotlin, php, python, ruby) that reference client.bulk() and were breaking the example compile/test checks. Co-Authored-By: Claude Opus 4.8 --------- Co-authored-by: Claude Opus 4.8 --- .stats.yml | 8 +- src/Bulk/BulkAddUsersParams.php | 82 ------- src/Bulk/BulkCreateJobParams.php | 91 -------- src/Bulk/BulkGetJobResponse.php | 70 ------ src/Bulk/BulkGetJobResponse/Job.php | 151 ------------- src/Bulk/BulkGetJobResponse/Job/Status.php | 16 -- src/Bulk/BulkListUsersParams.php | 60 ----- src/Bulk/BulkListUsersResponse.php | 91 -------- src/Bulk/BulkListUsersResponse/Item.php | 199 ----------------- .../BulkListUsersResponse/Item/Status.php | 14 -- src/Bulk/BulkNewJobResponse.php | 62 ------ src/Bulk/InboundBulkMessage.php | 209 ------------------ src/Bulk/InboundBulkMessage/Content.php | 34 --- src/Bulk/InboundBulkMessageUser.php | 158 ------------- src/Client.php | 7 - src/ServiceContracts/BulkContract.php | 92 -------- src/ServiceContracts/BulkRawContract.php | 100 --------- src/Services/BulkRawService.php | 193 ---------------- src/Services/BulkService.php | 158 ------------- tests/Services/BulkTest.php | 198 ----------------- 20 files changed, 4 insertions(+), 1989 deletions(-) delete mode 100644 src/Bulk/BulkAddUsersParams.php delete mode 100644 src/Bulk/BulkCreateJobParams.php delete mode 100644 src/Bulk/BulkGetJobResponse.php delete mode 100644 src/Bulk/BulkGetJobResponse/Job.php delete mode 100644 src/Bulk/BulkGetJobResponse/Job/Status.php delete mode 100644 src/Bulk/BulkListUsersParams.php delete mode 100644 src/Bulk/BulkListUsersResponse.php delete mode 100644 src/Bulk/BulkListUsersResponse/Item.php delete mode 100644 src/Bulk/BulkListUsersResponse/Item/Status.php delete mode 100644 src/Bulk/BulkNewJobResponse.php delete mode 100644 src/Bulk/InboundBulkMessage.php delete mode 100644 src/Bulk/InboundBulkMessage/Content.php delete mode 100644 src/Bulk/InboundBulkMessageUser.php delete mode 100644 src/ServiceContracts/BulkContract.php delete mode 100644 src/ServiceContracts/BulkRawContract.php delete mode 100644 src/Services/BulkRawService.php delete mode 100644 src/Services/BulkService.php delete mode 100644 tests/Services/BulkTest.php diff --git a/.stats.yml b/.stats.yml index 44174988..e2794c72 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 139 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b03f5346718dcd7b22f15893445ea593ab87535c90c540fc5a796c6ecd54d779.yml -openapi_spec_hash: 15677d3be4ecd33eab154080b4bc437f -config_hash: dcd58abf1e56b114bdce22336ca3d570 +configured_endpoints: 134 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b053468fefe6d757f86f3233ebbc52d80329ed2a6e7a6740fee01e4028a4c3b9.yml +openapi_spec_hash: 416835e693de0fe19945be90a787d3f3 +config_hash: 8d28dbeabe9d4dcc7d5b8c021a4cbbd7 diff --git a/src/Bulk/BulkAddUsersParams.php b/src/Bulk/BulkAddUsersParams.php deleted file mode 100644 index 3c4082c1..00000000 --- a/src/Bulk/BulkAddUsersParams.php +++ /dev/null @@ -1,82 +0,0 @@ - - * } - */ -final class BulkAddUsersParams implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - use SdkParams; - - /** @var list $users */ - #[Required(list: InboundBulkMessageUser::class)] - public array $users; - - /** - * `new BulkAddUsersParams()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * BulkAddUsersParams::with(users: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new BulkAddUsersParams)->withUsers(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param list $users - */ - public static function with(array $users): self - { - $self = new self; - - $self['users'] = $users; - - return $self; - } - - /** - * @param list $users - */ - public function withUsers(array $users): self - { - $self = clone $this; - $self['users'] = $users; - - return $self; - } -} diff --git a/src/Bulk/BulkCreateJobParams.php b/src/Bulk/BulkCreateJobParams.php deleted file mode 100644 index c903353a..00000000 --- a/src/Bulk/BulkCreateJobParams.php +++ /dev/null @@ -1,91 +0,0 @@ - */ - use SdkModel; - use SdkParams; - - /** - * Bulk message definition. Supports two formats: - * - V1 format: Requires `event` field (event ID or notification ID) - * - V2 format: Optionally use `template` (notification ID) or `content` (Elemental content) in addition to `event` - */ - #[Required] - public InboundBulkMessage $message; - - /** - * `new BulkCreateJobParams()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * BulkCreateJobParams::with(message: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new BulkCreateJobParams)->withMessage(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param InboundBulkMessage|InboundBulkMessageShape $message - */ - public static function with(InboundBulkMessage|array $message): self - { - $self = new self; - - $self['message'] = $message; - - return $self; - } - - /** - * Bulk message definition. Supports two formats: - * - V1 format: Requires `event` field (event ID or notification ID) - * - V2 format: Optionally use `template` (notification ID) or `content` (Elemental content) in addition to `event` - * - * @param InboundBulkMessage|InboundBulkMessageShape $message - */ - public function withMessage(InboundBulkMessage|array $message): self - { - $self = clone $this; - $self['message'] = $message; - - return $self; - } -} diff --git a/src/Bulk/BulkGetJobResponse.php b/src/Bulk/BulkGetJobResponse.php deleted file mode 100644 index 3274c613..00000000 --- a/src/Bulk/BulkGetJobResponse.php +++ /dev/null @@ -1,70 +0,0 @@ - */ - use SdkModel; - - #[Required] - public Job $job; - - /** - * `new BulkGetJobResponse()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * BulkGetJobResponse::with(job: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new BulkGetJobResponse)->withJob(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param Job|JobShape $job - */ - public static function with(Job|array $job): self - { - $self = new self; - - $self['job'] = $job; - - return $self; - } - - /** - * @param Job|JobShape $job - */ - public function withJob(Job|array $job): self - { - $self = clone $this; - $self['job'] = $job; - - return $self; - } -} diff --git a/src/Bulk/BulkGetJobResponse/Job.php b/src/Bulk/BulkGetJobResponse/Job.php deleted file mode 100644 index a42e24c3..00000000 --- a/src/Bulk/BulkGetJobResponse/Job.php +++ /dev/null @@ -1,151 +0,0 @@ -, - * } - */ -final class Job implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** - * Bulk message definition. Supports two formats: - * - V1 format: Requires `event` field (event ID or notification ID) - * - V2 format: Optionally use `template` (notification ID) or `content` (Elemental content) in addition to `event` - */ - #[Required] - public InboundBulkMessage $definition; - - #[Required] - public int $enqueued; - - #[Required] - public int $failures; - - #[Required] - public int $received; - - /** @var value-of $status */ - #[Required(enum: Status::class)] - public string $status; - - /** - * `new Job()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * Job::with( - * definition: ..., enqueued: ..., failures: ..., received: ..., status: ... - * ) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new Job) - * ->withDefinition(...) - * ->withEnqueued(...) - * ->withFailures(...) - * ->withReceived(...) - * ->withStatus(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param InboundBulkMessage|InboundBulkMessageShape $definition - * @param Status|value-of $status - */ - public static function with( - InboundBulkMessage|array $definition, - int $enqueued, - int $failures, - int $received, - Status|string $status, - ): self { - $self = new self; - - $self['definition'] = $definition; - $self['enqueued'] = $enqueued; - $self['failures'] = $failures; - $self['received'] = $received; - $self['status'] = $status; - - return $self; - } - - /** - * Bulk message definition. Supports two formats: - * - V1 format: Requires `event` field (event ID or notification ID) - * - V2 format: Optionally use `template` (notification ID) or `content` (Elemental content) in addition to `event` - * - * @param InboundBulkMessage|InboundBulkMessageShape $definition - */ - public function withDefinition(InboundBulkMessage|array $definition): self - { - $self = clone $this; - $self['definition'] = $definition; - - return $self; - } - - public function withEnqueued(int $enqueued): self - { - $self = clone $this; - $self['enqueued'] = $enqueued; - - return $self; - } - - public function withFailures(int $failures): self - { - $self = clone $this; - $self['failures'] = $failures; - - return $self; - } - - public function withReceived(int $received): self - { - $self = clone $this; - $self['received'] = $received; - - return $self; - } - - /** - * @param Status|value-of $status - */ - public function withStatus(Status|string $status): self - { - $self = clone $this; - $self['status'] = $status; - - return $self; - } -} diff --git a/src/Bulk/BulkGetJobResponse/Job/Status.php b/src/Bulk/BulkGetJobResponse/Job/Status.php deleted file mode 100644 index 712f1bc3..00000000 --- a/src/Bulk/BulkGetJobResponse/Job/Status.php +++ /dev/null @@ -1,16 +0,0 @@ - */ - use SdkModel; - use SdkParams; - - /** - * A unique identifier that allows for fetching the next set of users added to the bulk job. - */ - #[Optional(nullable: true)] - public ?string $cursor; - - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - */ - public static function with(?string $cursor = null): self - { - $self = new self; - - null !== $cursor && $self['cursor'] = $cursor; - - return $self; - } - - /** - * A unique identifier that allows for fetching the next set of users added to the bulk job. - */ - public function withCursor(?string $cursor): self - { - $self = clone $this; - $self['cursor'] = $cursor; - - return $self; - } -} diff --git a/src/Bulk/BulkListUsersResponse.php b/src/Bulk/BulkListUsersResponse.php deleted file mode 100644 index 9665398e..00000000 --- a/src/Bulk/BulkListUsersResponse.php +++ /dev/null @@ -1,91 +0,0 @@ -, paging: Paging|PagingShape - * } - */ -final class BulkListUsersResponse implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** @var list $items */ - #[Required(list: Item::class)] - public array $items; - - #[Required] - public Paging $paging; - - /** - * `new BulkListUsersResponse()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * BulkListUsersResponse::with(items: ..., paging: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new BulkListUsersResponse)->withItems(...)->withPaging(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param list $items - * @param Paging|PagingShape $paging - */ - public static function with(array $items, Paging|array $paging): self - { - $self = new self; - - $self['items'] = $items; - $self['paging'] = $paging; - - return $self; - } - - /** - * @param list $items - */ - public function withItems(array $items): self - { - $self = clone $this; - $self['items'] = $items; - - return $self; - } - - /** - * @param Paging|PagingShape $paging - */ - public function withPaging(Paging|array $paging): self - { - $self = clone $this; - $self['paging'] = $paging; - - return $self; - } -} diff --git a/src/Bulk/BulkListUsersResponse/Item.php b/src/Bulk/BulkListUsersResponse/Item.php deleted file mode 100644 index eb4bf319..00000000 --- a/src/Bulk/BulkListUsersResponse/Item.php +++ /dev/null @@ -1,199 +0,0 @@ -|null, - * recipient?: string|null, - * to?: null|UserRecipient|UserRecipientShape, - * status: Status|value-of, - * messageID?: string|null, - * } - */ -final class Item implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** - * User-specific data that will be merged with message.data. - */ - #[Optional] - public mixed $data; - - #[Optional] - public ?RecipientPreferences $preferences; - - /** - * User profile information. For email-based bulk jobs, `profile.email` is required - * for provider routing to determine if the message can be delivered. The email - * address should be provided here rather than in `to.email`. - * - * @var array|null $profile - */ - #[Optional(map: 'mixed', nullable: true)] - public ?array $profile; - - /** - * User ID (legacy field, use profile or to.user_id instead). - */ - #[Optional(nullable: true)] - public ?string $recipient; - - #[Optional] - public ?UserRecipient $to; - - /** @var value-of $status */ - #[Required(enum: Status::class)] - public string $status; - - #[Optional('messageId', nullable: true)] - public ?string $messageID; - - /** - * `new Item()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * Item::with(status: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new Item)->withStatus(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param Status|value-of $status - * @param RecipientPreferences|RecipientPreferencesShape|null $preferences - * @param array|null $profile - * @param UserRecipient|UserRecipientShape|null $to - */ - public static function with( - Status|string $status, - mixed $data = null, - RecipientPreferences|array|null $preferences = null, - ?array $profile = null, - ?string $recipient = null, - UserRecipient|array|null $to = null, - ?string $messageID = null, - ): self { - $self = new self; - - $self['status'] = $status; - - null !== $data && $self['data'] = $data; - null !== $preferences && $self['preferences'] = $preferences; - null !== $profile && $self['profile'] = $profile; - null !== $recipient && $self['recipient'] = $recipient; - null !== $to && $self['to'] = $to; - null !== $messageID && $self['messageID'] = $messageID; - - return $self; - } - - /** - * User-specific data that will be merged with message.data. - */ - public function withData(mixed $data): self - { - $self = clone $this; - $self['data'] = $data; - - return $self; - } - - /** - * @param RecipientPreferences|RecipientPreferencesShape $preferences - */ - public function withPreferences( - RecipientPreferences|array $preferences - ): self { - $self = clone $this; - $self['preferences'] = $preferences; - - return $self; - } - - /** - * User profile information. For email-based bulk jobs, `profile.email` is required - * for provider routing to determine if the message can be delivered. The email - * address should be provided here rather than in `to.email`. - * - * @param array|null $profile - */ - public function withProfile(?array $profile): self - { - $self = clone $this; - $self['profile'] = $profile; - - return $self; - } - - /** - * User ID (legacy field, use profile or to.user_id instead). - */ - public function withRecipient(?string $recipient): self - { - $self = clone $this; - $self['recipient'] = $recipient; - - return $self; - } - - /** - * @param UserRecipient|UserRecipientShape $to - */ - public function withTo(UserRecipient|array $to): self - { - $self = clone $this; - $self['to'] = $to; - - return $self; - } - - /** - * @param Status|value-of $status - */ - public function withStatus(Status|string $status): self - { - $self = clone $this; - $self['status'] = $status; - - return $self; - } - - public function withMessageID(?string $messageID): self - { - $self = clone $this; - $self['messageID'] = $messageID; - - return $self; - } -} diff --git a/src/Bulk/BulkListUsersResponse/Item/Status.php b/src/Bulk/BulkListUsersResponse/Item/Status.php deleted file mode 100644 index 886feb96..00000000 --- a/src/Bulk/BulkListUsersResponse/Item/Status.php +++ /dev/null @@ -1,14 +0,0 @@ - */ - use SdkModel; - - #[Required('jobId')] - public string $jobID; - - /** - * `new BulkNewJobResponse()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * BulkNewJobResponse::with(jobID: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new BulkNewJobResponse)->withJobID(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - */ - public static function with(string $jobID): self - { - $self = new self; - - $self['jobID'] = $jobID; - - return $self; - } - - public function withJobID(string $jobID): self - { - $self = clone $this; - $self['jobID'] = $jobID; - - return $self; - } -} diff --git a/src/Bulk/InboundBulkMessage.php b/src/Bulk/InboundBulkMessage.php deleted file mode 100644 index 5d07e712..00000000 --- a/src/Bulk/InboundBulkMessage.php +++ /dev/null @@ -1,209 +0,0 @@ -|null, - * locale?: array>|null, - * override?: array|null, - * template?: string|null, - * } - */ -final class InboundBulkMessage implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** - * Event ID or Notification ID (required). Can be either a - * Notification ID (e.g., "FRH3QXM9E34W4RKP7MRC8NZ1T8V8") or a custom Event ID - * (e.g., "welcome-email") mapped to a notification. - */ - #[Required] - public string $event; - - #[Optional(nullable: true)] - public ?string $brand; - - /** - * Elemental content (optional, for V2 format). When provided, this will be used - * instead of the notification associated with the `event` field. - * - * @var ContentVariants|null $content - */ - #[Optional(nullable: true)] - public ElementalContentSugar|ElementalContent|null $content; - - /** @var array|null $data */ - #[Optional(map: 'mixed', nullable: true)] - public ?array $data; - - /** @var array>|null $locale */ - #[Optional(map: new MapOf('mixed'), nullable: true)] - public ?array $locale; - - /** @var array|null $override */ - #[Optional(map: 'mixed', nullable: true)] - public ?array $override; - - /** - * Notification ID or template ID (optional, for V2 format). When provided, - * this will be used instead of the notification associated with the `event` field. - */ - #[Optional(nullable: true)] - public ?string $template; - - /** - * `new InboundBulkMessage()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * InboundBulkMessage::with(event: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new InboundBulkMessage)->withEvent(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param ContentShape|null $content - * @param array|null $data - * @param array>|null $locale - * @param array|null $override - */ - public static function with( - string $event, - ?string $brand = null, - ElementalContentSugar|array|ElementalContent|null $content = null, - ?array $data = null, - ?array $locale = null, - ?array $override = null, - ?string $template = null, - ): self { - $self = new self; - - $self['event'] = $event; - - null !== $brand && $self['brand'] = $brand; - null !== $content && $self['content'] = $content; - null !== $data && $self['data'] = $data; - null !== $locale && $self['locale'] = $locale; - null !== $override && $self['override'] = $override; - null !== $template && $self['template'] = $template; - - return $self; - } - - /** - * Event ID or Notification ID (required). Can be either a - * Notification ID (e.g., "FRH3QXM9E34W4RKP7MRC8NZ1T8V8") or a custom Event ID - * (e.g., "welcome-email") mapped to a notification. - */ - public function withEvent(string $event): self - { - $self = clone $this; - $self['event'] = $event; - - return $self; - } - - public function withBrand(?string $brand): self - { - $self = clone $this; - $self['brand'] = $brand; - - return $self; - } - - /** - * Elemental content (optional, for V2 format). When provided, this will be used - * instead of the notification associated with the `event` field. - * - * @param ContentShape|null $content - */ - public function withContent( - ElementalContentSugar|array|ElementalContent|null $content - ): self { - $self = clone $this; - $self['content'] = $content; - - return $self; - } - - /** - * @param array|null $data - */ - public function withData(?array $data): self - { - $self = clone $this; - $self['data'] = $data; - - return $self; - } - - /** - * @param array>|null $locale - */ - public function withLocale(?array $locale): self - { - $self = clone $this; - $self['locale'] = $locale; - - return $self; - } - - /** - * @param array|null $override - */ - public function withOverride(?array $override): self - { - $self = clone $this; - $self['override'] = $override; - - return $self; - } - - /** - * Notification ID or template ID (optional, for V2 format). When provided, - * this will be used instead of the notification associated with the `event` field. - */ - public function withTemplate(?string $template): self - { - $self = clone $this; - $self['template'] = $template; - - return $self; - } -} diff --git a/src/Bulk/InboundBulkMessage/Content.php b/src/Bulk/InboundBulkMessage/Content.php deleted file mode 100644 index aab7554b..00000000 --- a/src/Bulk/InboundBulkMessage/Content.php +++ /dev/null @@ -1,34 +0,0 @@ -|array - */ - public static function variants(): array - { - return [ElementalContentSugar::class, ElementalContent::class]; - } -} diff --git a/src/Bulk/InboundBulkMessageUser.php b/src/Bulk/InboundBulkMessageUser.php deleted file mode 100644 index 970668be..00000000 --- a/src/Bulk/InboundBulkMessageUser.php +++ /dev/null @@ -1,158 +0,0 @@ -|null, - * recipient?: string|null, - * to?: null|UserRecipient|UserRecipientShape, - * } - */ -final class InboundBulkMessageUser implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** - * User-specific data that will be merged with message.data. - */ - #[Optional] - public mixed $data; - - #[Optional(nullable: true)] - public ?RecipientPreferences $preferences; - - /** - * User profile information. For email-based bulk jobs, `profile.email` is required - * for provider routing to determine if the message can be delivered. The email - * address should be provided here rather than in `to.email`. - * - * @var array|null $profile - */ - #[Optional(map: 'mixed', nullable: true)] - public ?array $profile; - - /** - * User ID (legacy field, use profile or to.user_id instead). - */ - #[Optional(nullable: true)] - public ?string $recipient; - - /** - * Optional recipient information. Note: For email provider routing, use - * `profile.email` instead of `to.email`. The `to` field is primarily used - * for recipient identification and data merging. - */ - #[Optional(nullable: true)] - public ?UserRecipient $to; - - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param RecipientPreferences|RecipientPreferencesShape|null $preferences - * @param array|null $profile - * @param UserRecipient|UserRecipientShape|null $to - */ - public static function with( - mixed $data = null, - RecipientPreferences|array|null $preferences = null, - ?array $profile = null, - ?string $recipient = null, - UserRecipient|array|null $to = null, - ): self { - $self = new self; - - null !== $data && $self['data'] = $data; - null !== $preferences && $self['preferences'] = $preferences; - null !== $profile && $self['profile'] = $profile; - null !== $recipient && $self['recipient'] = $recipient; - null !== $to && $self['to'] = $to; - - return $self; - } - - /** - * User-specific data that will be merged with message.data. - */ - public function withData(mixed $data): self - { - $self = clone $this; - $self['data'] = $data; - - return $self; - } - - /** - * @param RecipientPreferences|RecipientPreferencesShape|null $preferences - */ - public function withPreferences( - RecipientPreferences|array|null $preferences - ): self { - $self = clone $this; - $self['preferences'] = $preferences; - - return $self; - } - - /** - * User profile information. For email-based bulk jobs, `profile.email` is required - * for provider routing to determine if the message can be delivered. The email - * address should be provided here rather than in `to.email`. - * - * @param array|null $profile - */ - public function withProfile(?array $profile): self - { - $self = clone $this; - $self['profile'] = $profile; - - return $self; - } - - /** - * User ID (legacy field, use profile or to.user_id instead). - */ - public function withRecipient(?string $recipient): self - { - $self = clone $this; - $self['recipient'] = $recipient; - - return $self; - } - - /** - * Optional recipient information. Note: For email provider routing, use - * `profile.email` instead of `to.email`. The `to` field is primarily used - * for recipient identification and data merging. - * - * @param UserRecipient|UserRecipientShape|null $to - */ - public function withTo(UserRecipient|array|null $to): self - { - $self = clone $this; - $self['to'] = $to; - - return $self; - } -} diff --git a/src/Client.php b/src/Client.php index 75981579..a9f5518f 100644 --- a/src/Client.php +++ b/src/Client.php @@ -12,7 +12,6 @@ use Courier\Services\AuthService; use Courier\Services\AutomationsService; use Courier\Services\BrandsService; -use Courier\Services\BulkService; use Courier\Services\DigestsService; use Courier\Services\InboundService; use Courier\Services\JourneysService; @@ -79,11 +78,6 @@ class Client extends BaseClient */ public BrandsService $brands; - /** - * @api - */ - public BulkService $bulk; - /** * @api */ @@ -208,7 +202,6 @@ public function __construct( $this->automations = new AutomationsService($this); $this->journeys = new JourneysService($this); $this->brands = new BrandsService($this); - $this->bulk = new BulkService($this); $this->digests = new DigestsService($this); $this->inbound = new InboundService($this); $this->lists = new ListsService($this); diff --git a/src/ServiceContracts/BulkContract.php b/src/ServiceContracts/BulkContract.php deleted file mode 100644 index 80367eab..00000000 --- a/src/ServiceContracts/BulkContract.php +++ /dev/null @@ -1,92 +0,0 @@ - $users - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function addUsers( - string $jobID, - array $users, - RequestOptions|array|null $requestOptions = null, - ): mixed; - - /** - * @api - * - * @param InboundBulkMessage|InboundBulkMessageShape $message Bulk message definition. Supports two formats: - * - V1 format: Requires `event` field (event ID or notification ID) - * - V2 format: Optionally use `template` (notification ID) or `content` (Elemental content) in addition to `event` - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function createJob( - InboundBulkMessage|array $message, - RequestOptions|array|null $requestOptions = null, - ): BulkNewJobResponse; - - /** - * @api - * - * @param string $jobID A unique identifier representing the bulk job - * @param string|null $cursor A unique identifier that allows for fetching the next set of users added to the bulk job - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function listUsers( - string $jobID, - ?string $cursor = null, - RequestOptions|array|null $requestOptions = null, - ): BulkListUsersResponse; - - /** - * @api - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function retrieveJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): BulkGetJobResponse; - - /** - * @api - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function runJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): mixed; -} diff --git a/src/ServiceContracts/BulkRawContract.php b/src/ServiceContracts/BulkRawContract.php deleted file mode 100644 index 7145d750..00000000 --- a/src/ServiceContracts/BulkRawContract.php +++ /dev/null @@ -1,100 +0,0 @@ -|BulkAddUsersParams $params - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function addUsers( - string $jobID, - array|BulkAddUsersParams $params, - RequestOptions|array|null $requestOptions = null, - ): BaseResponse; - - /** - * @api - * - * @param array|BulkCreateJobParams $params - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function createJob( - array|BulkCreateJobParams $params, - RequestOptions|array|null $requestOptions = null, - ): BaseResponse; - - /** - * @api - * - * @param string $jobID A unique identifier representing the bulk job - * @param array|BulkListUsersParams $params - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function listUsers( - string $jobID, - array|BulkListUsersParams $params, - RequestOptions|array|null $requestOptions = null, - ): BaseResponse; - - /** - * @api - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function retrieveJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): BaseResponse; - - /** - * @api - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function runJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): BaseResponse; -} diff --git a/src/Services/BulkRawService.php b/src/Services/BulkRawService.php deleted file mode 100644 index aadfadb4..00000000 --- a/src/Services/BulkRawService.php +++ /dev/null @@ -1,193 +0,0 @@ - - * }|BulkAddUsersParams $params - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function addUsers( - string $jobID, - array|BulkAddUsersParams $params, - RequestOptions|array|null $requestOptions = null, - ): BaseResponse { - [$parsed, $options] = BulkAddUsersParams::parseRequest( - $params, - $requestOptions, - ); - - // @phpstan-ignore-next-line return.type - return $this->client->request( - method: 'post', - path: ['bulk/%1$s', $jobID], - body: (object) $parsed, - options: $options, - convert: null, - ); - } - - /** - * @api - * - * Creates a new bulk job for sending messages to multiple recipients. - * - * **Required**: `message.event` (event ID or notification ID) - * - * **Optional (V2 format)**: `message.template` (notification ID) or `message.content` (Elemental content) - * can be provided to override the notification associated with the event. - * - * @param array{ - * message: InboundBulkMessage|InboundBulkMessageShape - * }|BulkCreateJobParams $params - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function createJob( - array|BulkCreateJobParams $params, - RequestOptions|array|null $requestOptions = null, - ): BaseResponse { - [$parsed, $options] = BulkCreateJobParams::parseRequest( - $params, - $requestOptions, - ); - - // @phpstan-ignore-next-line return.type - return $this->client->request( - method: 'post', - path: 'bulk', - body: (object) $parsed, - options: $options, - convert: BulkNewJobResponse::class, - ); - } - - /** - * @api - * - * Get Bulk Job Users - * - * @param string $jobID A unique identifier representing the bulk job - * @param array{cursor?: string|null}|BulkListUsersParams $params - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function listUsers( - string $jobID, - array|BulkListUsersParams $params, - RequestOptions|array|null $requestOptions = null, - ): BaseResponse { - [$parsed, $options] = BulkListUsersParams::parseRequest( - $params, - $requestOptions, - ); - - // @phpstan-ignore-next-line return.type - return $this->client->request( - method: 'get', - path: ['bulk/%1$s/users', $jobID], - query: $parsed, - options: $options, - convert: BulkListUsersResponse::class, - ); - } - - /** - * @api - * - * Get a bulk job - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function retrieveJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): BaseResponse { - // @phpstan-ignore-next-line return.type - return $this->client->request( - method: 'get', - path: ['bulk/%1$s', $jobID], - options: $requestOptions, - convert: BulkGetJobResponse::class, - ); - } - - /** - * @api - * - * Run a bulk job - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @return BaseResponse - * - * @throws APIException - */ - public function runJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): BaseResponse { - // @phpstan-ignore-next-line return.type - return $this->client->request( - method: 'post', - path: ['bulk/%1$s/run', $jobID], - options: $requestOptions, - convert: null, - ); - } -} diff --git a/src/Services/BulkService.php b/src/Services/BulkService.php deleted file mode 100644 index 8bae11d7..00000000 --- a/src/Services/BulkService.php +++ /dev/null @@ -1,158 +0,0 @@ -raw = new BulkRawService($client); - } - - /** - * @api - * - * Ingest user data into a Bulk Job. - * - * **Important**: For email-based bulk jobs, each user must include `profile.email` - * for provider routing to work correctly. The `to.email` field is not sufficient - * for email provider routing. - * - * @param string $jobID A unique identifier representing the bulk job - * @param list $users - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function addUsers( - string $jobID, - array $users, - RequestOptions|array|null $requestOptions = null, - ): mixed { - $params = Util::removeNulls(['users' => $users]); - - // @phpstan-ignore-next-line argument.type - $response = $this->raw->addUsers($jobID, params: $params, requestOptions: $requestOptions); - - return $response->parse(); - } - - /** - * @api - * - * Creates a new bulk job for sending messages to multiple recipients. - * - * **Required**: `message.event` (event ID or notification ID) - * - * **Optional (V2 format)**: `message.template` (notification ID) or `message.content` (Elemental content) - * can be provided to override the notification associated with the event. - * - * @param InboundBulkMessage|InboundBulkMessageShape $message Bulk message definition. Supports two formats: - * - V1 format: Requires `event` field (event ID or notification ID) - * - V2 format: Optionally use `template` (notification ID) or `content` (Elemental content) in addition to `event` - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function createJob( - InboundBulkMessage|array $message, - RequestOptions|array|null $requestOptions = null, - ): BulkNewJobResponse { - $params = Util::removeNulls(['message' => $message]); - - // @phpstan-ignore-next-line argument.type - $response = $this->raw->createJob(params: $params, requestOptions: $requestOptions); - - return $response->parse(); - } - - /** - * @api - * - * Get Bulk Job Users - * - * @param string $jobID A unique identifier representing the bulk job - * @param string|null $cursor A unique identifier that allows for fetching the next set of users added to the bulk job - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function listUsers( - string $jobID, - ?string $cursor = null, - RequestOptions|array|null $requestOptions = null, - ): BulkListUsersResponse { - $params = Util::removeNulls(['cursor' => $cursor]); - - // @phpstan-ignore-next-line argument.type - $response = $this->raw->listUsers($jobID, params: $params, requestOptions: $requestOptions); - - return $response->parse(); - } - - /** - * @api - * - * Get a bulk job - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function retrieveJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): BulkGetJobResponse { - // @phpstan-ignore-next-line argument.type - $response = $this->raw->retrieveJob($jobID, requestOptions: $requestOptions); - - return $response->parse(); - } - - /** - * @api - * - * Run a bulk job - * - * @param string $jobID A unique identifier representing the bulk job - * @param RequestOpts|null $requestOptions - * - * @throws APIException - */ - public function runJob( - string $jobID, - RequestOptions|array|null $requestOptions = null - ): mixed { - // @phpstan-ignore-next-line argument.type - $response = $this->raw->runJob($jobID, requestOptions: $requestOptions); - - return $response->parse(); - } -} diff --git a/tests/Services/BulkTest.php b/tests/Services/BulkTest.php deleted file mode 100644 index 8a8fcbc2..00000000 --- a/tests/Services/BulkTest.php +++ /dev/null @@ -1,198 +0,0 @@ -client = $client; - } - - #[Test] - public function testAddUsers(): void - { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Mock server tests are disabled'); - } - - $result = $this->client->bulk->addUsers('job_id', users: [[]]); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNull($result); - } - - #[Test] - public function testAddUsersWithOptionalParams(): void - { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Mock server tests are disabled'); - } - - $result = $this->client->bulk->addUsers( - 'job_id', - users: [ - [ - 'data' => (object) [], - 'preferences' => [ - 'categories' => [ - 'foo' => [ - 'status' => PreferenceStatus::OPTED_IN, - 'channelPreferences' => [ - ['channel' => ChannelClassification::DIRECT_MESSAGE], - ], - 'rules' => [['until' => 'until', 'start' => 'start']], - ], - ], - 'notifications' => [ - 'foo' => [ - 'status' => PreferenceStatus::OPTED_IN, - 'channelPreferences' => [ - ['channel' => ChannelClassification::DIRECT_MESSAGE], - ], - 'rules' => [['until' => 'until', 'start' => 'start']], - ], - ], - ], - 'profile' => ['foo' => 'bar'], - 'recipient' => 'recipient', - 'to' => [ - 'accountID' => 'account_id', - 'context' => ['tenantID' => 'tenant_id'], - 'data' => ['foo' => 'bar'], - 'email' => 'email', - 'listID' => 'list_id', - 'locale' => 'locale', - 'phoneNumber' => 'phone_number', - 'preferences' => [ - 'notifications' => [ - 'foo' => [ - 'status' => PreferenceStatus::OPTED_IN, - 'channelPreferences' => [ - ['channel' => ChannelClassification::DIRECT_MESSAGE], - ], - 'rules' => [['until' => 'until', 'start' => 'start']], - 'source' => 'subscription', - ], - ], - 'categories' => [ - 'foo' => [ - 'status' => PreferenceStatus::OPTED_IN, - 'channelPreferences' => [ - ['channel' => ChannelClassification::DIRECT_MESSAGE], - ], - 'rules' => [['until' => 'until', 'start' => 'start']], - 'source' => 'subscription', - ], - ], - 'templateID' => 'templateId', - ], - 'tenantID' => 'tenant_id', - 'userID' => 'user_id', - ], - ], - ], - ); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNull($result); - } - - #[Test] - public function testCreateJob(): void - { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Mock server tests are disabled'); - } - - $result = $this->client->bulk->createJob(message: ['event' => 'event']); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(BulkNewJobResponse::class, $result); - } - - #[Test] - public function testCreateJobWithOptionalParams(): void - { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Mock server tests are disabled'); - } - - $result = $this->client->bulk->createJob( - message: [ - 'event' => 'event', - 'brand' => 'brand', - 'content' => ['body' => 'body', 'title' => 'title'], - 'data' => ['foo' => 'bar'], - 'locale' => ['foo' => ['foo' => 'bar']], - 'override' => ['foo' => 'bar'], - 'template' => 'template', - ], - ); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(BulkNewJobResponse::class, $result); - } - - #[Test] - public function testListUsers(): void - { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Mock server tests are disabled'); - } - - $result = $this->client->bulk->listUsers('job_id'); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(BulkListUsersResponse::class, $result); - } - - #[Test] - public function testRetrieveJob(): void - { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Mock server tests are disabled'); - } - - $result = $this->client->bulk->retrieveJob('job_id'); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(BulkGetJobResponse::class, $result); - } - - #[Test] - public function testRunJob(): void - { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Mock server tests are disabled'); - } - - $result = $this->client->bulk->runJob('job_id'); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNull($result); - } -} From 0889c2e49d3a2fc445efcefde39b51375626d6f0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 19:48:39 +0000 Subject: [PATCH 2/2] release: 5.13.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ src/Version.php | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8f918e4b..242d5048 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "5.12.0" + ".": "5.13.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b31308a..5148519a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 5.13.0 (2026-07-23) + +Full Changelog: [v5.12.0...v5.13.0](https://github.com/trycourier/courier-php/compare/v5.12.0...v5.13.0) + +### Features + +* Remove /bulk endpoints from api-spec (C-19507) ([#171](https://github.com/trycourier/courier-php/issues/171)) ([b39cce7](https://github.com/trycourier/courier-php/commit/b39cce702c9b4ae9ff04011530f9f9fd16e793b3)) + ## 5.12.0 (2026-07-20) Full Changelog: [v5.11.2...v5.12.0](https://github.com/trycourier/courier-php/compare/v5.11.2...v5.12.0) diff --git a/src/Version.php b/src/Version.php index 2f86aeaa..6ba3204c 100644 --- a/src/Version.php +++ b/src/Version.php @@ -5,5 +5,5 @@ namespace Courier; // x-release-please-start-version -const VERSION = '5.12.0'; +const VERSION = '5.13.0'; // x-release-please-end