diff --git a/docs/Webhooks.md b/docs/Webhooks.md index 195ce8d..2fff630 100644 --- a/docs/Webhooks.md +++ b/docs/Webhooks.md @@ -37,6 +37,8 @@ Every delivery carries a [`WebhookEvent`](../src/API/Resources/WebhookEvent.php) | `entityType` | `string` | Type of the related resource (e.g. `order`, `refund`, `subscription`). | | `entityId` | `string` | ID of the related resource (e.g. `order_Hn5xWqVfKm8RjTgYbUcP`). | | `object` | `object\|null` | The full resource payload at the time of the event. Shape depends on `entityType`. | +| `createdAt` | `string` | When the event occurred (ISO 8601). | +| `testmode` | `bool` | Whether this event was generated in test mode. | | `links` | `object` | HATEOAS links — `links.self.href` points to this webhook event. | ### Example payload @@ -54,6 +56,8 @@ Every delivery carries a [`WebhookEvent`](../src/API/Resources/WebhookEvent.php) "status": "paid", "total": { "value": "29.99", "currency": "EUR" } }, + "createdAt": "2026-01-11T10:50:50+02:00", + "testmode": true, "links": { "self": { "href": "https://api.vatly.com/v1/webhook-events/webhook_event_Qk8pRtSvWm2NjLhYcZaE", diff --git a/src/API/Resources/WebhookEvent.php b/src/API/Resources/WebhookEvent.php index 3dee113..83380d5 100644 --- a/src/API/Resources/WebhookEvent.php +++ b/src/API/Resources/WebhookEvent.php @@ -47,5 +47,12 @@ class WebhookEvent extends BaseResource */ public $object = null; + /** + * @example 2023-08-11T10:48:51+02:00 + */ + public string $createdAt; + + public bool $testmode; + public WebhookEventLinks $links; } diff --git a/src/API/Webhooks/Webhook.php b/src/API/Webhooks/Webhook.php index 1205266..c6f274f 100644 --- a/src/API/Webhooks/Webhook.php +++ b/src/API/Webhooks/Webhook.php @@ -35,7 +35,7 @@ public static function parse(string $payload, string $signature, string $secret) ); } - foreach (['id', 'resource', 'eventName', 'entityType', 'entityId'] as $field) { + foreach (['id', 'resource', 'eventName', 'entityType', 'entityId', 'createdAt', 'testmode'] as $field) { if (! isset($decoded->{$field})) { throw new \InvalidArgumentException( "Webhook payload is missing required field: {$field}" @@ -56,6 +56,8 @@ public static function parse(string $payload, string $signature, string $secret) $decoded->eventName, $decoded->entityType, $decoded->entityId, + $decoded->testmode, + $decoded->createdAt, $object, ); } diff --git a/src/API/Webhooks/WebhookPayload.php b/src/API/Webhooks/WebhookPayload.php index 977aa82..108a6d0 100644 --- a/src/API/Webhooks/WebhookPayload.php +++ b/src/API/Webhooks/WebhookPayload.php @@ -54,12 +54,21 @@ class WebhookPayload */ public ?object $object; + /** + * @example 2023-08-11T10:48:51+02:00 + */ + public string $createdAt; + + public bool $testmode; + public function __construct( string $id, string $resource, string $eventName, string $entityType, string $entityId, + bool $testmode, + string $createdAt, ?object $object = null, ) { $this->id = $id; @@ -68,5 +77,7 @@ public function __construct( $this->entityType = $entityType; $this->entityId = $entityId; $this->object = $object; + $this->testmode = $testmode; + $this->createdAt = $createdAt; } } diff --git a/tests/Webhooks/WebhookTest.php b/tests/Webhooks/WebhookTest.php index 1ecb615..ee7138f 100644 --- a/tests/Webhooks/WebhookTest.php +++ b/tests/Webhooks/WebhookTest.php @@ -23,6 +23,8 @@ private function makePayload(array $overrides = []): string 'entityType' => 'order', 'entityId' => 'order_Hn5xWqVfKm8RjTgYbUcP', 'object' => ['id' => 'order_Hn5xWqVfKm8RjTgYbUcP', 'resource' => 'order'], + 'createdAt' => '2023-01-11T10:50:50+02:00', + 'testmode' => true, ], $overrides); return json_encode($data); @@ -52,6 +54,9 @@ public function test_it_parses_a_valid_webhook(): void $this->assertSame('order_Hn5xWqVfKm8RjTgYbUcP', $event->entityId); $this->assertIsObject($event->object); $this->assertSame('order_Hn5xWqVfKm8RjTgYbUcP', $event->object->id); + $this->assertSame('order', $event->object->resource); + $this->assertTrue($event->testmode); + $this->assertSame('2023-01-11T10:50:50+02:00', $event->createdAt); } public function test_it_parses_a_webhook_without_object(): void @@ -62,6 +67,8 @@ public function test_it_parses_a_webhook_without_object(): void 'eventName' => 'order.paid', 'entityType' => 'order', 'entityId' => 'order_Hn5xWqVfKm8RjTgYbUcP', + 'createdAt' => '2023-01-11T10:50:50+02:00', + 'testmode' => true, ]; $payload = json_encode($data); $signature = $this->sign($payload);