diff --git a/.env.dist.testing b/.env.dist.testing
index f61980a..3acd54e 100644
--- a/.env.dist.testing
+++ b/.env.dist.testing
@@ -12,3 +12,4 @@ CONVERTKIT_API_TAG_NAME_2="gravityforms-tag-1"
CONVERTKIT_API_TAG_ID_2="2907192"
CONVERTKIT_API_SUBSCRIBER_EMAIL="optin@n7studios.com"
CONVERTKIT_API_SUBSCRIBER_ID="1579118532"
+CONVERTKIT_API_EMAIL_TEMPLATE_ID="2201089"
diff --git a/phpcs.xml b/phpcs.xml
index 3b059b2..9a763a5 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -72,7 +72,7 @@
-
+
diff --git a/src/ConvertKit_API_Traits.php b/src/ConvertKit_API_Traits.php
index 92c8abd..b1131f8 100644
--- a/src/ConvertKit_API_Traits.php
+++ b/src/ConvertKit_API_Traits.php
@@ -415,6 +415,156 @@ public function get_sequences(
);
}
+ /**
+ * Create a sequence
+ *
+ * @param string $name The name of the sequence.
+ * @param string $email_address The sending email address to use. Uses the account's sending email address if not provided.
+ * @param integer $email_template_id Id of the email template to use.
+ * @param array $send_days The days of the week to send the sequence on. Must be one of: `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday`.
+ * @param integer $send_hour The hour of the day to send the sequence at. Must be an integer between 0 and 23.
+ * @param string $time_zone The timezone to use for the sequence. Must be a valid IANA timezone string.
+ * @param boolean $active Use `true` to activate the sequence, `false` to deactivate it.
+ * @param boolean $repeat When `true`, subscribers can restart the sequence multiple times.
+ * @param boolean $hold When `true`, subscribers added via Visual Automations stay in the sequence after receiving the last email.
+ * @param array> $exclude_subscriber_sources The subscriber sources to exclude from the sequence. Uses the account's default exclude subscriber sources if not provided.
+ *
+ * @see https://developers.kit.com/api-reference/sequences/create-a-sequence
+ *
+ * @return mixed|object
+ */
+ public function create_sequence(
+ string $name,
+ string $email_address = '',
+ int $email_template_id = 0,
+ array $send_days = [],
+ int $send_hour = 0,
+ string $time_zone = '',
+ bool $active = true,
+ bool $repeat = false,
+ bool $hold = false,
+ array $exclude_subscriber_sources = []
+ ) {
+ $options = [
+ 'name' => $name,
+ 'email_address' => $email_address,
+ 'email_template_id' => $email_template_id,
+ 'send_hour' => $send_hour,
+ 'time_zone' => $time_zone,
+ 'active' => $active,
+ 'repeat' => $repeat,
+ 'hold' => $hold,
+ ];
+ if (count($send_days)) {
+ $options['send_days'] = $send_days;
+ }
+ if (count($exclude_subscriber_sources)) {
+ $options['exclude_subscriber_sources'] = $exclude_subscriber_sources;
+ }
+
+ // Iterate through options, removing blank entries.
+ foreach ($options as $key => $value) {
+ if (is_string($value) && strlen($value) === 0) {
+ unset($options[$key]);
+ }
+ }
+
+ // Send request.
+ return $this->post(
+ 'sequences',
+ $options
+ );
+ }
+
+ /**
+ * Get a sequence.
+ *
+ * @param integer $id Sequence ID.
+ *
+ * @see https://developers.kit.com/api-reference/sequences/get-a-sequence
+ *
+ * @return mixed|object
+ */
+ public function get_sequence(int $id)
+ {
+ return $this->get(sprintf('sequences/%s', $id));
+ }
+
+ /**
+ * Updates a sequence
+ *
+ * @param integer $sequence_id Sequence ID.
+ * @param string $name The name of the sequence.
+ * @param string $email_address The sending email address to use. Uses the account's sending email address if not provided.
+ * @param integer $email_template_id Id of the email template to use.
+ * @param array $send_days The days of the week to send the sequence on. Must be one of: `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday`.
+ * @param integer $send_hour The hour of the day to send the sequence at. Must be an integer between 0 and 23.
+ * @param string $time_zone The timezone to use for the sequence. Must be a valid IANA timezone string.
+ * @param boolean $active Use `true` to activate the sequence, `false` to deactivate it.
+ * @param boolean $repeat When `true`, subscribers can restart the sequence multiple times.
+ * @param boolean $hold When `true`, subscribers added via Visual Automations stay in the sequence after receiving the last email.
+ * @param array> $exclude_subscriber_sources The subscriber sources to exclude from the sequence. Uses the account's default exclude subscriber sources if not provided.
+ *
+ * @see https://developers.kit.com/api-reference/sequences/create-a-sequence
+ *
+ * @return mixed|object
+ */
+ public function update_sequence(
+ int $sequence_id,
+ string $name = '',
+ string $email_address = '',
+ int $email_template_id = 0,
+ array $send_days = [],
+ int $send_hour = 0,
+ string $time_zone = '',
+ bool $active = true,
+ bool $repeat = false,
+ bool $hold = false,
+ array $exclude_subscriber_sources = []
+ ) {
+ $options = [
+ 'name' => $name,
+ 'email_address' => $email_address,
+ 'email_template_id' => $email_template_id,
+ 'send_days' => $send_days,
+ 'send_hour' => $send_hour,
+ 'time_zone' => $time_zone,
+ 'active' => $active,
+ 'repeat' => $repeat,
+ 'hold' => $hold,
+ ];
+ if (count($exclude_subscriber_sources)) {
+ $options['exclude_subscriber_sources'] = $exclude_subscriber_sources;
+ }
+
+ // Iterate through options, removing blank entries.
+ foreach ($options as $key => $value) {
+ if (is_string($value) && strlen($value) === 0) {
+ unset($options[$key]);
+ }
+ }
+
+ // Send request.
+ return $this->put(
+ sprintf('sequences/%s', $sequence_id),
+ $options
+ );
+ }
+
+ /**
+ * Deletes a sequence.
+ *
+ * @param integer $id Sequence ID.
+ *
+ * @see https://developers.kit.com/api-reference/sequences/delete-a-sequence
+ *
+ * @return mixed|object
+ */
+ public function delete_sequence(int $id)
+ {
+ return $this->delete(sprintf('sequences/%s', $id));
+ }
+
/**
* Adds subscriber to sequence by email address
*
@@ -2067,8 +2217,8 @@ public function post(string $endpoint, array $args = [])
/**
* Performs a PUT request to the API.
*
- * @param string $endpoint API Endpoint.
- * @param array|string> $args Request arguments.
+ * @param string $endpoint API Endpoint.
+ * @param array|boolean|integer|float|string>> $args Request arguments.
*
* @return false|mixed
*/
diff --git a/tests/ConvertKitAPITest.php b/tests/ConvertKitAPITest.php
index 8259adc..0fa5e42 100644
--- a/tests/ConvertKitAPITest.php
+++ b/tests/ConvertKitAPITest.php
@@ -1059,6 +1059,135 @@ public function testGetSequencesPagination()
$this->assertCount(1, $result->sequences);
}
+ /**
+ * Test that create_sequence(), update_sequence() and delete_sequence() works.
+ *
+ * We do all tests in a single function, so we don't end up with unnecessary
+ * Sequences remaining on the Kit account when running tests, which might impact
+ * other tests that expect (or do not expect) specific Sequences.
+ *
+ * @since 2.5.0
+ *
+ * @return void
+ */
+ public function testCreateUpdateAndDeleteSequence()
+ {
+ // Create a sequence.
+ $result = $this->api->create_sequence(
+ name: 'Test Sequence',
+ email_address: 'wordpress@convertkit.com',
+ email_template_id: (int) $_ENV['CONVERTKIT_API_EMAIL_TEMPLATE_ID'],
+ send_days: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'],
+ send_hour: 12,
+ time_zone: 'America/Los_Angeles',
+ active: false,
+ repeat: false,
+ hold: false
+ );
+ $sequenceID = $result->sequence->id;
+
+ // Confirm the Sequence saved.
+ $result = get_object_vars($result->sequence);
+ $this->assertArrayHasKey('id', $result);
+ $this->assertEquals('Test Sequence', $result['name']);
+ $this->assertEquals('wordpress@convertkit.com', $result['email_address']);
+ $this->assertEquals((int) $_ENV['CONVERTKIT_API_EMAIL_TEMPLATE_ID'], $result['email_template_id']);
+ $this->assertEquals(['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], $result['send_days']);
+ $this->assertEquals(12, $result['send_hour']);
+ $this->assertEquals('America/Los_Angeles', $result['time_zone']);
+ $this->assertEquals(false, $result['active']);
+ $this->assertEquals(false, $result['repeat']);
+ $this->assertEquals(false, $result['hold']);
+
+ // Update the existing sequence.
+ $result = $this->api->update_sequence(
+ sequence_id: $sequenceID,
+ name: 'Edited Test Sequence',
+ email_address: 'wordpress@convertkit.com',
+ email_template_id: (int) $_ENV['CONVERTKIT_API_EMAIL_TEMPLATE_ID'],
+ send_days: ['saturday', 'sunday'],
+ send_hour: 13,
+ time_zone: 'America/New_York',
+ active: true,
+ repeat: true,
+ hold: true
+ );
+
+ // Confirm the changes saved.
+ $result = get_object_vars($result->sequence);
+ $this->assertArrayHasKey('id', $result);
+ $this->assertEquals('Edited Test Sequence', $result['name']);
+ $this->assertEquals('wordpress@convertkit.com', $result['email_address']);
+ $this->assertEquals((int) $_ENV['CONVERTKIT_API_EMAIL_TEMPLATE_ID'], $result['email_template_id']);
+ $this->assertEquals(['saturday', 'sunday'], $result['send_days']);
+ $this->assertEquals(13, $result['send_hour']);
+ $this->assertEquals('America/New_York', $result['time_zone']);
+ $this->assertEquals(true, $result['active']);
+ $this->assertEquals(true, $result['repeat']);
+ $this->assertEquals(true, $result['hold']);
+
+ // Delete Sequence.
+ $this->api->delete_sequence($sequenceID);
+ $this->assertEquals(204, $this->api->getResponseInterface()->getStatusCode());
+ }
+
+ /**
+ * Test that get_sequence() returns the expected data.
+ *
+ * @since 2.5.0
+ *
+ * @return void
+ */
+ public function testGetSequence()
+ {
+ $result = $this->api->get_sequence((int) $_ENV['CONVERTKIT_API_SEQUENCE_ID']);
+ $this->assertInstanceOf('stdClass', $result);
+ $this->assertArrayHasKey('sequence', get_object_vars($result));
+ $this->assertArrayHasKey('id', get_object_vars($result->sequence));
+ }
+
+ /**
+ * Test that get_sequence() throws a ClientException when an invalid
+ * sequence ID is specified.
+ *
+ * @since 2.5.0
+ *
+ * @return void
+ */
+ public function testGetSequenceWithInvalidSequenceID()
+ {
+ $this->expectException(ClientException::class);
+ $this->api->get_sequence(12345);
+ }
+
+ /**
+ * Test that update_sequence() throws a ClientException when an invalid
+ * sequence ID is specified.
+ *
+ * @since 2.5.0
+ *
+ * @return void
+ */
+ public function testUpdateSequenceWithInvalidSequenceID()
+ {
+ $this->expectException(ClientException::class);
+ $this->api->update_sequence(12345);
+ }
+
+ /**
+ * Test that delete_sequence() throws a ClientException when an invalid
+ * sequence ID is specified.
+ *
+ * @since 2.5.0
+ *
+ * @return void
+ */
+ public function testDeleteSequenceWithInvalidSequenceID()
+ {
+ $this->expectException(ClientException::class);
+ $this->api->delete_sequence(12345);
+ }
+
/**
* Test that add_subscriber_to_sequence_by_email() returns the expected data.
*