تخطَّ إلى المستندات
PHP

$client->webhooks

كل دالّة في مساحة الأسماء هذه: توقيعها ومعلماتها وما تُرجعه ومثال عليها.

الدوالّ

Endpoints that receive signed mailbox events: register, change, test and remove them, rotate their secrets, read and replay their delivery log, and follow their audit log and delivery numbers. OpenEmail::verifyWebhookSignature checks each delivery.

webhooks->list

List the webhook endpoints in the workspace

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
list(?int $limit = null, ?string $cursor = null, ?string $apiKey = null): Page

Returns one page of the webhook endpoints registered on the key's workspace, newest first. webhooks->listAll collects every page and webhooks->iterate walks them lazily.

Signing secrets are never part of a read. Only webhooks->create and webhooks->rotateSecret return secret, so a lost secret cannot be recovered from here. An endpoint subscribed to every event, which is what an endpoint created without eventTypes is, reports eventTypes as ['*'] rather than an empty array.

Read enabled, disabledReason and consecutiveFailures as the health summary. An endpoint the server switched off after 100 consecutive failed deliveries shows enabled false with disabledAt and a reason, while one you disabled yourself through webhooks->update has both of those null.

المعلمات

limitint

Page size, from 1 to 100. The server defaults to 25.

cursorstring

The nextCursor of the previous page. Leave it out for the first page.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

A Page of endpoint arrays, with items, hasMore and nextCursor. Each item has id, url, description, eventTypes, enabled, disabledAt, disabledReason, consecutiveFailures, addressAllowlist, domainAllowlist, lastDeliveryAt and createdAt.

مثال

$page = $client->webhooks->list(); foreach ($page as $endpoint) {    $health = $endpoint['enabled']        ? $endpoint['consecutiveFailures'] . ' failures in a row'        : 'off, ' . ($endpoint['disabledReason'] ?? 'switched off by hand');     echo $endpoint['url'], ': ', implode(', ', $endpoint['eventTypes']), ', ', $health, PHP_EOL;}

ملاحظات

  • A narrowed key reads every endpoint, and may write one whose own addressAllowlist and domainAllowlist sit inside what the key holds. A write that would take an endpoint wider than the key is 422 capability_unsupported on addressAllowlist.

  • lastDeliveryAt moves on failed attempts as well as successful ones, so it shows the endpoint is being called, not that it is healthy.

  • The cursor is opaque and holds where the last row sat in this order, so a row deleted or edited between pages never breaks the walk: the next page starts at the first row that sorts after it. A cursor this list did not hand out is a 400 invalid_cursor.

متاح أيضًا في

API
GET /webhooks
TypeScript
webhooks.list()
Python
webhooks.list()
Ruby
webhooks.list
CLI
openemail webhooks list

webhooks->listAll

Collect every webhook endpoint into one array

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listAll(?int $limit = null, ?string $cursor = null, ?string $apiKey = null): array

Walks every page of webhooks->list and returns all webhook endpoints in one array, newest first. One request per page.

المعلمات

limitint

Page size for each request, from 1 to 100. The server defaults to 25.

cursorstring

Starts the walk after this cursor instead of the first page.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A list of endpoint arrays holding every webhook endpoint.

مثال

$endpoints = $client->webhooks->listAll(); $switchedOff = array_filter($endpoints, static fn(array $endpoint): bool => $endpoint['disabledAt'] !== null); echo count($endpoints), ' endpoints, ', count($switchedOff), ' switched off by the server', PHP_EOL;

ملاحظات

  • If any page fails, the exception is thrown and the webhook endpoints already fetched are discarded.

متاح أيضًا في

API
GET /webhooks
TypeScript
webhooks.listAll()
Python
webhooks.list_all()
Ruby
webhooks.list_all

webhooks->iterate

Stream the webhook endpoints one at a time

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
iterate(?int $limit = null, ?string $cursor = null, ?string $apiKey = null): Generator

Returns a Generator that yields webhook endpoints one at a time, newest first, and requests the next page only once the current one is used up. Nothing is fetched until the loop starts, and breaking out of the foreach stops the requests.

المعلمات

limitint

Page size for each request, from 1 to 100. The server defaults to 25.

cursorstring

Starts the walk after this cursor instead of the first page.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A Generator that yields one endpoint array per step.

مثال

foreach ($client->webhooks->iterate() as $endpoint) {    if (!$endpoint['enabled'] && $endpoint['disabledAt'] !== null) {        echo $endpoint['url'], ' was switched off: ', $endpoint['disabledReason'], PHP_EOL;    }}

ملاحظات

  • The generator is lazy, so an abandoned loop costs only the pages you consumed.

متاح أيضًا في

API
GET /webhooks
TypeScript
webhooks.iterate()
Python
webhooks.iterate()
Ruby
webhooks.iterate

webhooks->get

Read one webhook endpoint by id

الصلاحياتwebhooks:read
التوقيع
get(string $id, ?string $apiKey = null): array

Returns a single endpoint with its URL, subscription list, enabled state and delivery health. The signing secret is never part of a read. It appears only in the responses of webhooks->create and webhooks->rotateSecret, and a lost one is replaced with webhooks->rotateSecret rather than read back.

An id from another workspace answers exactly like one that never existed, with 404 resource_not_found, so a 404 does not tell you whether the endpoint was deleted or was never yours.

consecutiveFailures resets to 0 on any successful delivery and when webhooks->update sets enabled to true. When it reaches 100 the server disables the endpoint, fills in disabledAt and disabledReason, and emails the workspace owner and every member whose role can read webhooks.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array with id, url, description, eventTypes, enabled, disabledAt, disabledReason, consecutiveFailures, addressAllowlist, domainAllowlist, lastDeliveryAt and createdAt. No secret.

مثال

$endpoint = $client->webhooks->get('whe_3f9c2a7b1e4d8f60a5c7b92d'); echo $endpoint['url'], $endpoint['enabled'] ? ' is on' : ' is off', ', last called ', $endpoint['lastDeliveryAt'] ?? 'never', PHP_EOL; if ($endpoint['eventTypes'] === ['*']) {    echo 'It receives the default email events', PHP_EOL;}

ملاحظات

  • eventTypes of ['*'] means the endpoint named none, so it receives the default email.* set. email.replied, domain.*, suppression.*, file.* and form.* sit outside that set and have to be named explicitly.

  • A GET is retried automatically on network failure and on 408, 429, 500, 502, 503 and 504 responses, up to the client's maxRetries.

متاح أيضًا في

API
GET /webhooks/{id}
TypeScript
webhooks.get()
Python
webhooks.get()
Ruby
webhooks.get
CLI
openemail webhooks get

webhooks->create

Register an HTTPS endpoint for mailbox events

الصلاحياتwebhooks:write
التوقيع
create(array $body, ?string $apiKey = null): array

Registers a receiver URL and subscribes it to events on the key's workspace. The endpoint starts enabled, so the next matching event is delivered to it straight away. Leave eventTypes out, or pass an empty array, and the endpoint receives the default set, which is the email.* events other than email.replied. Every family outside it has to be named: email.replied, domain.*, suppression.*, file.* and form.*. Reads report an unnamed subscription as ['*'].

By default an endpoint hears about every address the workspace owns. addressAllowlist and domainAllowlist narrow it, exactly as the same two lists narrow an API key: name whole domains, single addresses, or both. An event reaches the endpoint when the address or domain it concerns is covered. Events that name no address at all, such as suppression.removed, reach every endpoint whatever its lists say. form.* is the exception: a sign-up belongs to the whole workspace, so an endpoint limited to some addresses or domains never receives form.submitted or form.confirmed.

This response is the only place the full secret ever appears. Every later read omits it, so store it before doing anything else, and if it is lost call webhooks->rotateSecret. The secret is whsec_ followed by 43 base64url characters, and the HMAC key is the whole string including the prefix, so pass it to OpenEmail::verifyWebhookSignature exactly as returned.

url must be https. localhost, hosts ending .localhost, .internal or .local, and IP literals in loopback, private, link local, carrier grade NAT, multicast or unique local ranges are refused with 422 invalid_webhook_url. The host is resolved again on every delivery, and an attempt to a name that resolves into one of those ranges is recorded as failed without being sent. Deliveries never follow redirects, so register the final address.

المعلمات

urlstringمطلوب

The https receiver URL. Another scheme or a blocked host is 422 invalid_webhook_url. Stored in normalised form, so the url read back can differ cosmetically.

eventTypesstring[]

Events to subscribe to, also in OpenEmail\Constants\WebhookEvents. Omit it, or send [], for the default email.* set: email.received, email.sent, email.failed, email.cancelled, email.scheduled, email.queued, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.suppressed, email.opened, email.clicked and email.downloaded. email.replied, domain.verified, domain.sending_changed, domain.deleted, suppression.added, suppression.removed, file.uploaded, file.deleted, form.submitted and form.confirmed are outside that set and have to be named.

descriptionstring

Free text note, at most 200 characters.

addressAllowliststring[]

Single addresses this endpoint hears about. An event is delivered when the address it concerns is on this list, or when its domain is in domainAllowlist. Leave both empty and the endpoint hears about every address the workspace owns. At most 50, and an address this workspace does not own is 422 invalid_parameter.

domainAllowliststring[]

Whole domains this endpoint hears about, including addresses added to them later. A domain also carries its own domain.* events. At most 25. An address whose domain is already listed here is dropped from addressAllowlist when the endpoint is saved, so the two lists never overlap.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array for the endpoint plus the plaintext secret: id, url, description, eventTypes, enabled, disabledAt, disabledReason, consecutiveFailures, addressAllowlist, domainAllowlist, lastDeliveryAt, createdAt and secret.

مثال

use OpenEmail\Constants\WebhookEvents; $endpoint = $client->webhooks->create([    'url' => 'https://hooks.acme.com/openemail',    'eventTypes' => [WebhookEvents::EMAIL_BOUNCED, WebhookEvents::EMAIL_COMPLAINED, WebhookEvents::EMAIL_REPLIED],    'description' => 'Bounces, complaints and replies',    'domainAllowlist' => ['acme.com'],]); file_put_contents('.webhook-secret', $endpoint['secret']); echo 'Created ', $endpoint['id'], ' for ', implode(', ', $endpoint['eventTypes']), PHP_EOL;

ملاحظات

  • Verify each delivery with OpenEmail::verifyWebhookSignature($payload, $headers, $secret), passing the raw request body, such as file_get_contents('php://input'), and the request headers as an array, $_SERVER or a PSR-7 request. It checks the X-OpenEmail-Signature HMAC-SHA256 over the timestamp, a dot and the raw body in constant time, rejects a timestamp more than 300 seconds off, throws a WebhookSignatureException on failure and returns the event as an array with id, type, createdAt and data.

  • Each attempt is one POST with a 5 second timeout. A failure worth repeating (no answer, 408, 425, 429 or a 5xx) is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours, up to 8 attempts over about 27 and a half hours, each wait varied by up to 10% and stretched when your server's Retry-After asks for longer, up to 6 hours. A 410 Gone switches the endpoint off. webhooks->listDeliveries shows every attempt with its number, and webhooks->replayDelivery sends one of them again, one event at a time, once your receiver is fixed.

  • A workspace holds 10 endpoints by default, and support can raise that for a workspace that needs more. The next one past the limit is 422 workspace_limit_reached. A narrowed key may create an endpoint, but only one whose own lists sit inside what the key holds. Anything wider is 422 capability_unsupported on addressAllowlist.

  • Not retried automatically, so a network failure can leave an endpoint created with a secret you never saw. Check webhooks->list before creating it again.

متاح أيضًا في

API
POST /webhooks
TypeScript
webhooks.create()
Python
webhooks.create()
Ruby
webhooks.create
CLI
openemail webhooks create

webhooks->update

Change an endpoint URL, events or enabled state

الصلاحياتwebhooks:write
التوقيع
update(string $id, array $patch, ?string $apiKey = null): array

Patches the URL, subscription list, description or enabled flag of one endpoint. Every field is optional, and an empty patch is accepted and changes nothing you can read back. A new url goes through the same https and host checks as webhooks->create, and 'description' => null clears the note.

eventTypes replaces the subscription set wholesale, so send the complete list you want rather than a delta. An empty array does not unsubscribe: it puts the endpoint back on the default email.* set. To stop deliveries, set enabled to false instead.

addressAllowlist and domainAllowlist replace the endpoint's scope the same way, wholesale rather than as a delta. Send both empty to widen it back to every address the workspace owns. Each list is checked against the domains and addresses this workspace actually owns, and an unknown one is 422 invalid_parameter.

Writing enabled clears disabledAt and disabledReason either way, so an endpoint you switch off yourself reports both as null. Setting it back to true also resets consecutiveFailures to 0, which is how an endpoint the server disabled after 100 failures is brought back. Events that fire while an endpoint is disabled are never delivered to it later, but a delivery that failed before it was switched off can be sent again with webhooks->replayDelivery once it is back on, one event at a time.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

urlstring

Replacement https URL, checked against the same host rules as webhooks->create.

eventTypesstring[]

Complete replacement subscription set. [] means the default email.* set.

addressAllowliststring[]

Complete replacement list of single addresses this endpoint hears about. At most 50. Send [] on both lists to hear about every address again.

domainAllowliststring[]

Complete replacement list of whole domains this endpoint hears about, including addresses added to them later. At most 25.

descriptionstring|null

Replacement note of at most 200 characters, or null to clear it.

enabledbool

False stops deliveries. True resumes them and resets consecutiveFailures.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array for the endpoint as saved. The signing secret is untouched and not included.

مثال

use OpenEmail\Constants\WebhookEvents; $endpoint = $client->webhooks->update('whe_3f9c2a7b1e4d8f60a5c7b92d', [    'url' => 'https://hooks.acme.com/openemail/v2',    'eventTypes' => [WebhookEvents::EMAIL_BOUNCED, WebhookEvents::EMAIL_COMPLAINED],    'enabled' => true,]); echo $endpoint['url'], ' now hears ', implode(', ', $endpoint['eventTypes']), PHP_EOL;

ملاحظات

  • Read the current eventTypes first if you mean to add one, since a partial list silently unsubscribes the rest. The same applies to the two allowlists. Do not send back ['*'] as read: it is a 422 invalid_parameter, and [] is how to ask for the default set.

  • This route never touches the signing secret. Use webhooks->rotateSecret for that.

  • Retried automatically on network failure and retryable statuses, since the same patch applied twice lands on the same row.

متاح أيضًا في

API
PATCH /webhooks/{id}
TypeScript
webhooks.update()
Python
webhooks.update()
Ruby
webhooks.update
CLI
openemail webhooks update

webhooks->delete

Delete an endpoint and its delivery log

الصلاحياتwebhooks:write
التوقيع
delete(string $id, ?string $apiKey = null): array

Removes the endpoint for good. Deliveries stop immediately, the signing secret is gone, and the delivery log for the endpoint is deleted with it, so read it with webhooks->listAllDeliveries first if you need it for an audit trail.

There is no undo and no soft delete. If the aim is only to pause deliveries, call webhooks->update with ['enabled' => false] and keep the endpoint, its secret and its log.

The response is a tombstone rather than an empty body, so a log line can name what went. Deleting frees a slot against the workspace's endpoint limit straight away.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array with object set to webhook, the id and deleted set to true.

مثال

$log = $client->webhooks->listAllDeliveries('whe_3f9c2a7b1e4d8f60a5c7b92d', limit: 100); file_put_contents('webhook-log.json', json_encode($log, JSON_PRETTY_PRINT)); $deleted = $client->webhooks->delete('whe_3f9c2a7b1e4d8f60a5c7b92d'); echo 'Deleted ', $deleted['id'], ' after saving ', count($log), ' deliveries', PHP_EOL;

ملاحظات

  • Not idempotent: a second call on the same id is 404 resource_not_found, and the SDK does not retry it after a network failure.

  • A narrowed key may delete only an endpoint whose own allowlists sit inside what the key holds. Any other is 422 capability_unsupported on addressAllowlist.

متاح أيضًا في

API
DELETE /webhooks/{id}
TypeScript
webhooks.delete()
Python
webhooks.delete()
Ruby
webhooks.delete
CLI
openemail webhooks delete

webhooks->rotateSecret

Issue a new signing secret for an endpoint

الصلاحياتwebhooks:write
التوقيع
rotateSecret(string $id, ?string $apiKey = null): array

Generates a new signing secret and returns the endpoint plus the new plaintext secret. As with webhooks->create, this response is the only place that secret appears, so store it before anything else.

There is no overlap window. Every delivery is signed at send time with the current secret, so the old one stops verifying the moment this call commits, and any event that fires before your receiver has the new secret fails verification on your side.

The safe order is to deploy a receiver that tries both the old secret and a new one read from config, call this, write the returned secret to config, then drop the old one. webhooks->test confirms the new secret verifies before you remove the fallback.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array for the full endpoint plus the new secret, formatted whsec_ followed by 43 base64url characters.

مثال

$rotated = $client->webhooks->rotateSecret('whe_3f9c2a7b1e4d8f60a5c7b92d'); file_put_contents('.webhook-secret', $rotated['secret']); $check = $client->webhooks->test($rotated['id']); echo 'A test signed with the new secret: ', $check['delivery']['status'] ?? 'not recorded', PHP_EOL;

ملاحظات

  • There is no request body and the success status is 200, not 201.

  • Not retried automatically. A lost response means a secret you never saw is already live, so rotate again rather than waiting.

  • Subscriptions, enabled state and consecutiveFailures are left as they were.

متاح أيضًا في

API
POST /webhooks/{id}/rotate-secret
TypeScript
webhooks.rotateSecret()
Python
webhooks.rotate_secret()
Ruby
webhooks.rotate_secret
CLI
openemail webhooks rotate-secret

webhooks->test

Send a synthetic event and report how delivery went

الصلاحياتwebhooks:write
التوقيع
test(string $id, ?string $apiKey = null): array

Posts a signed synthetic email.sent event to the endpoint and waits for the attempt to finish before returning. The payload data holds test set to true and a note, and no mail is sent, so it is safe against a production receiver. It proves the URL is reachable and that your signature check accepts the current secret before real mail depends on it.

The outcome comes back as delivery, read from the newest row of the delivery log. status is delivered for any 2xx answer and failed otherwise, responseCode is the HTTP status or null when no response arrived, such as a DNS failure or the 5 second timeout, and error explains a failure. A 3xx counts as failed because redirects are never followed.

The event goes out whatever the endpoint subscribes to, and even when it is disabled. It is recorded like any delivery, so it appears in webhooks->listDeliveries and can be sent again with webhooks->replayDelivery, but it is tried once and leaves consecutiveFailures and lastDeliveryAt alone, so a failing test never counts toward the 100 that disable an endpoint. A 410 Gone answer does switch the endpoint off, as it would for a real event.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array with object set to webhook_test, the endpoint id, and delivery holding status, responseCode, durationMs and error, or null when no delivery row could be read back.

مثال

$result = $client->webhooks->test('whe_3f9c2a7b1e4d8f60a5c7b92d'); $delivery = $result['delivery']; if ($delivery === null) {    echo 'No delivery row was recorded', PHP_EOL;} elseif ($delivery['status'] === 'delivered') {    echo 'Delivered in ', $delivery['durationMs'], ' ms', PHP_EOL;} else {    echo 'Failed with ', $delivery['responseCode'] ?? 'no response', ': ', $delivery['error'], PHP_EOL;}

ملاحظات

  • The call returns 200 when your receiver fails. Branch on $result['delivery']['status'], not on whether the call threw.

  • A 4xx from your receiver is a useful answer: the URL is reachable and the rejection came from your own handler, often its signature check.

  • Not retried automatically, since every call sends another request to your receiver.

  • If a real event reaches the same endpoint at the same moment, delivery can describe that attempt instead, because it reads the newest log row.

متاح أيضًا في

API
POST /webhooks/{id}/test
TypeScript
webhooks.test()
Python
webhooks.test()
Ruby
webhooks.test
CLI
openemail webhooks test

webhooks->listDeliveries

List one page of delivery attempts for one endpoint

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listDeliveries(    string $id,    ?string $status = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Page

Returns one page of an endpoint's delivery log, newest first. Nothing is dropped from the log, so following nextCursor while hasMore is true reaches the endpoint's very first delivery, and webhooks->listAllDeliveries and webhooks->iterateDeliveries do that walk for you. status:, since: and until: narrow it the way the Deliveries tab of the app does: status: 'failed' is its "only failed" switch.

Each attempt is one POST with a 5 second timeout, and one event can appear several times: when the failure is worth repeating, a delivery is tried up to 8 times, as it happens and then after 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours, about 27 and a half hours in all, and each webhooks->replayDelivery adds a row of its own. attempt and maxAttempts say which try a row is, and eventId is the same across all of them, so this log distinguishes a retry from a new event. nextAttemptAt is when the automatic retry that follows a row is due, and null when none is waiting, so a failed row with a time in it is not the final word. status is delivered for a 2xx answer and failed for anything else, including a 3xx, since redirects are not followed.

responseCode null means no response arrived, such as a DNS or TLS failure or the timeout, which is a different fact from a receiver that answered. durationMs is null only when the attempt was never made because the server could not read the signing secret, and error then says so. The body that was sent and your server's answer are not part of this response, and webhooks->getDelivery returns both. webhooks->listWorkspaceDeliveries reads every endpoint at once.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

statusstring

failed keeps only the attempts that did not get a 2xx, the "only failed" view of the app, and delivered keeps the rest.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Rows per page, a whole number from 1 to 100. The server defaults to 25.

cursorstring

The nextCursor from the previous page, passed back unchanged. Never build one yourself.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

A Page of delivery arrays, with items, hasMore and nextCursor. Each item has id, endpointId, eventType, eventId, status, responseCode, durationMs, attempt, maxAttempts, error, createdAt and nextAttemptAt.

مثال

$failed = $client->webhooks->listDeliveries('whe_3f9c2a7b1e4d8f60a5c7b92d', status: 'failed', since: new \DateTimeImmutable('-1 day')); foreach ($failed as $delivery) {    $next = $delivery['nextAttemptAt'] === null ? 'no retry due' : 'retry at ' . $delivery['nextAttemptAt'];     echo $delivery['eventType'], ' attempt ', $delivery['attempt'], ' of ', $delivery['maxAttempts'], ': ', $delivery['responseCode'] ?? 'no response', ', ', $next, PHP_EOL;}

ملاحظات

  • Synthetic events from webhooks->test appear here too, recorded as email.sent.

  • Each endpoint's copy of an event gets its own evt_ id, sent in the X-OpenEmail-Delivery header and as the payload id, and every retry and replay of that copy keeps it. One event fanned out to two endpoints arrives with two different ids, and a repeat to one endpoint arrives with the same one.

  • The cursor stays valid under every filter as long as each page sends the same status:, since: and until:, which webhooks->listAllDeliveries and webhooks->iterateDeliveries do for you.

  • A 404 resource_not_found means the endpoint id is wrong or belongs to another workspace, not that the log is empty. A cursor that names no delivery of this endpoint is a 400 invalid_cursor, and a since: or until: that does not parse is a 400 invalid_parameter.

متاح أيضًا في

API
GET /webhooks/{id}/deliveries
TypeScript
webhooks.listDeliveries()
Python
webhooks.list_deliveries()
Ruby
webhooks.list_deliveries
CLI
openemail webhooks list-deliveries

webhooks->listAllDeliveries

Collect an endpoint's whole delivery log into one array

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listAllDeliveries(    string $id,    ?string $status = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): array

Walks every page of an endpoint's delivery log and returns all of its attempts, newest first, under the same status:, since: and until: filters as webhooks->listDeliveries. The log is never pruned, so an endpoint that has been busy for a long time can hold a great many rows. Narrow it with a window, or prefer webhooks->iterateDeliveries when you can stop early.

Pages are keyset on createdAt and id, walking backwards in time. Attempts recorded after the walk starts are newer than its first page and are not included.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

statusstring

failed keeps only the attempts that did not get a 2xx, the "only failed" view of the app, and delivered keeps the rest.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size for each request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A list of delivery arrays holding every matching attempt on the endpoint, newest first.

مثال

$deliveries = $client->webhooks->listAllDeliveries('whe_3f9c2a7b1e4d8f60a5c7b92d', since: new \DateTimeImmutable('-7 days'), limit: 100); $failed = array_filter($deliveries, static fn(array $delivery): bool => $delivery['status'] === 'failed'); echo count($failed), ' of ', count($deliveries), ' attempts failed this week', PHP_EOL;

ملاحظات

  • If any page fails, the exception is thrown and the attempts already fetched are discarded.

  • One request per page, so a large log takes many requests. Read it with webhooks->iterateDeliveries to stop as soon as you have what you need.

متاح أيضًا في

API
GET /webhooks/{id}/deliveries
TypeScript
webhooks.listAllDeliveries()
Python
webhooks.list_all_deliveries()
Ruby
webhooks.list_all_deliveries

webhooks->iterateDeliveries

Stream an endpoint's delivery attempts one at a time, newest first

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
iterateDeliveries(    string $id,    ?string $status = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Generator

Returns a Generator over an endpoint's delivery log that yields attempts one at a time and fetches the next page only when the current one is used up, under the same status:, since: and until: filters as webhooks->listDeliveries. Nothing is requested until the loop starts, and breaking out of the foreach stops further requests, which makes it the right way to find the latest attempt of some kind without reading the whole history.

The walk ends when hasMore is false, when a page comes back empty, or when the server repeats a cursor. Attempts recorded after the walk starts are newer than its cursor and are not yielded.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

statusstring

failed keeps only the attempts that did not get a 2xx, the "only failed" view of the app, and delivered keeps the rest.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size per request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A Generator that yields one delivery array per step.

مثال

foreach ($client->webhooks->iterateDeliveries('whe_3f9c2a7b1e4d8f60a5c7b92d', status: 'failed') as $delivery) {    if ($delivery['nextAttemptAt'] === null) {        echo 'Latest final failure: ', $delivery['id'], ' ', $delivery['error'], PHP_EOL;         break;    }}

ملاحظات

  • The generator is lazy, so an abandoned loop costs only the pages you consumed.

متاح أيضًا في

API
GET /webhooks/{id}/deliveries
TypeScript
webhooks.iterateDeliveries()
Python
webhooks.iterate_deliveries()
Ruby
webhooks.iterate_deliveries

webhooks->getDelivery

Read one delivery attempt in full, with the body that was sent

الصلاحياتwebhooks:read
التوقيع
getDelivery(string $id, string $deliveryId, ?string $apiKey = null): array

Returns one attempt from an endpoint's delivery log with what webhooks->listDeliveries leaves out. payload is the exact JSON body that was POSTed, an array with id, type, createdAt and data, and responseBody is the first 2,000 characters your server answered, or null when nothing came back or the answer was a redirect.

attempts lists every try of the same event on this endpoint, oldest first: the first attempt, the automatic retries and any replays, each with its own id, attempt, status, responseCode, error and createdAt. They share eventId, which is the payload id your receiver saw. nextAttemptAt is when the next automatic retry of the event is due, whichever attempt it follows, and null when none is waiting.

replayRefusal says whether webhooks->replayDelivery would accept this attempt before you call it: null when it would, and otherwise the code and message the replay would be refused with, such as webhook_disabled while the endpoint is switched off, or retry_in_progress while an automatic retry of the same event is being sent.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

deliveryIdstringمطلوب

Delivery id, whd_ followed by 24 hex characters, as webhooks->listDeliveries returns it.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array with the delivery fields (id, eventType, eventId, status, responseCode, durationMs, attempt, maxAttempts, error, createdAt, nextAttemptAt) plus endpointId, payload, responseBody, attempts and replayRefusal.

مثال

$delivery = $client->webhooks->getDelivery('whe_3f9c2a7b1e4d8f60a5c7b92d', 'whd_8c1e4a7f2b9d3e6a0c5f1b28'); echo 'Event ', $delivery['payload']['id'], ' was tried ', count($delivery['attempts']), ' times', PHP_EOL;echo 'Your server answered: ', $delivery['responseBody'] ?? 'nothing', PHP_EOL; if ($delivery['replayRefusal'] !== null) {    echo 'A replay would be refused: ', $delivery['replayRefusal']['message'], PHP_EOL;}

ملاحظات

  • A delivery id that belongs to another endpoint, even one in the same workspace, is 404 resource_not_found, exactly like one that never existed.

  • Your server's answer is cut at 2,000 characters when it is recorded, so a longer one reads back truncated.

  • A GET is retried automatically on network failure and on 408, 429, 500, 502, 503 and 504 responses, up to the client's maxRetries.

  • A narrowed key may read a delivery only on an endpoint whose own allowlists sit inside what the key holds, where holding one address never covers its whole domain, because the body names the addresses the event is about. Any other is 422 capability_unsupported on addressAllowlist. Over OAuth only the workspace owner, or a member whose role holds addresses:all, may read one, and any other member's token is 403 owner_only. That member's token is held to the domains the workspace has now, so it reads only a delivery of an endpoint with allowlists, and one with none is 422 capability_unsupported for it too.

متاح أيضًا في

API
GET /webhooks/{id}/deliveries/{deliveryId}
TypeScript
webhooks.getDelivery()
Python
webhooks.get_delivery()
Ruby
webhooks.get_delivery
CLI
openemail webhooks get-delivery

webhooks->replayDelivery

Send one stored event to the endpoint again, now

الصلاحياتwebhooks:write
التوقيع
replayDelivery(string $id, string $deliveryId, ?string $apiKey = null): array

Posts the event behind a recorded attempt to the endpoint once more, straight away, and returns when that attempt has finished. The body is the one stored with the original, with the same id, type, createdAt and data, so a receiver that drops ids it has already handled treats the replay as the event it already knows. Only X-OpenEmail-Signature is new, because every POST is signed with the current secret at the moment it goes out, so a replay verifies after a webhooks->rotateSecret too.

It accepts a delivered attempt as well as a failed one. Replaying a success is how a receiver that lost its copy, or handled it wrongly, is brought back in step. Any attempt of the event will do, since they all carry the same event.

The replay is recorded in the log as a new delivery, attempt 1 of 1, and is never retried automatically. Before it goes out, the automatic retries of the same event that have not started are paused, so the receiver never gets two copies at once. When the replay is delivered they stay cancelled. When it fails they resume on their schedule. If an automatic retry of the event is being sent at that very moment, the replay sends nothing and is refused with 409 retry_in_progress, and if another replay of the same event is still being sent, it is refused with 409 replay_in_progress, so two copies never go out at once. The call returns 200 whatever your server answered, so branch on $replay['delivery']['status'] rather than on whether the call threw.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

deliveryIdstringمطلوب

Any attempt of the event to send again, whd_ followed by 24 hex characters.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array with object set to webhook_replay, id (the new delivery), endpointId, replayOf (the attempt you named), eventId, eventType, and delivery holding status, responseCode, durationMs and error.

مثال

use OpenEmail\Constants\WebhookReplayErrorCodes;use OpenEmail\Exception\ConflictException; try {    $replay = $client->webhooks->replayDelivery('whe_3f9c2a7b1e4d8f60a5c7b92d', 'whd_8c1e4a7f2b9d3e6a0c5f1b28');     $delivered = $replay['delivery']['status'] === 'delivered';     echo 'Replay ', $replay['id'], $delivered ? ' delivered' : ' failed: ' . $replay['delivery']['error'], PHP_EOL;} catch (ConflictException $error) {    if ($error->errorCode === WebhookReplayErrorCodes::RETRY_IN_PROGRESS) {        echo 'A retry of this event is being sent right now', PHP_EOL;    } else {        echo 'Refused: ', $error->errorCode, PHP_EOL;    }}

ملاحظات

  • Refused with 409 when nobody who wants the event would receive it: webhook_disabled while the endpoint is switched off, event_not_subscribed when it no longer listens for the event type, event_out_of_scope when its allowlists no longer cover the address the event is about, delivery_not_replayable when the attempt has no stored event, retry_in_progress while an automatic retry of the same event is being sent, and replay_in_progress while another replay of it is. The codes are in OpenEmail\Constants\WebhookReplayErrorCodes. Wait a few seconds and check webhooks->getDelivery before replaying again, since that retry or replay may deliver it. webhooks->getDelivery reports the same answer in advance as replayRefusal. A synthetic event from webhooks->test replays whatever the endpoint subscribes to.

  • Not retried automatically, because a retry after a lost response would send the event again. A receiver that drops repeated ids handles that safely, but the SDK does not assume yours does.

  • A delivered replay resets consecutiveFailures, and a failed one does not add to it. A 410 Gone switches the endpoint off, as it does for an automatic delivery.

  • A narrowed key may replay only on an endpoint whose own allowlists sit inside what the key holds. Any other is 422 capability_unsupported on addressAllowlist.

متاح أيضًا في

API
POST /webhooks/{id}/deliveries/{deliveryId}/replay
TypeScript
webhooks.replayDelivery()
Python
webhooks.replay_delivery()
Ruby
webhooks.replay_delivery
CLI
openemail webhooks replay-delivery

webhooks->listWorkspaceDeliveries

List one page of delivery attempts across every endpoint

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listWorkspaceDeliveries(    array|string|null $endpointIds = null,    ?string $status = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Page

Returns one page of the whole workspace's delivery log, newest first: the all-endpoints Deliveries tab of the app. Each row carries endpointId, so the endpoint an attempt went to is never lost. endpointIds: narrows it to some endpoints, and status:, since: and until: work exactly as they do on webhooks->listDeliveries.

Nothing is pruned, so following nextCursor while hasMore is true reaches the workspace's first delivery. webhooks->listAllWorkspaceDeliveries and webhooks->iterateWorkspaceDeliveries do that walk. The body that was sent is not here: read it with webhooks->getDelivery, passing the row's endpointId and id.

المعلمات

endpointIdsstring|string[]

Endpoint ids to read, at most 50, as a list or one comma-separated string. Left out, every endpoint in the workspace.

statusstring

failed keeps only the attempts that did not get a 2xx, the "only failed" view of the app, and delivered keeps the rest.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Rows per page, a whole number from 1 to 100. The server defaults to 25.

cursorstring

The nextCursor from the previous page, passed back unchanged. Never build one yourself.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

A Page of delivery arrays, with items, hasMore and nextCursor. Each item has id, endpointId, eventType, eventId, status, responseCode, durationMs, attempt, maxAttempts, error, createdAt and nextAttemptAt.

مثال

$page = $client->webhooks->listWorkspaceDeliveries(status: 'failed', since: new \DateTimeImmutable('-1 hour')); foreach ($page as $delivery) {    echo $delivery['endpointId'], ' ', $delivery['eventType'], ' ', $delivery['error'] ?? '', PHP_EOL;}

ملاحظات

  • An endpoint id in endpointIds: that belongs to no endpoint here simply matches nothing. A removed endpoint takes its deliveries with it.

  • The cursor stays valid under every filter as long as each page sends the same endpointIds:, status:, since: and until:, which webhooks->listAllWorkspaceDeliveries and webhooks->iterateWorkspaceDeliveries do for you.

  • The list carries no payloads, so a key narrowed to some addresses may read it. Opening a delivery with webhooks->getDelivery is where the narrowing applies.

متاح أيضًا في

API
GET /webhooks/deliveries
TypeScript
webhooks.listWorkspaceDeliveries()
Python
webhooks.list_workspace_deliveries()
Ruby
webhooks.list_workspace_deliveries
CLI
openemail webhooks list-workspace-deliveries

webhooks->listAllWorkspaceDeliveries

Collect the workspace's whole delivery log into one array

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listAllWorkspaceDeliveries(    array|string|null $endpointIds = null,    ?string $status = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): array

Walks every page of webhooks->listWorkspaceDeliveries under the same filters and returns every matching attempt, newest first. The log is never pruned, so give it a since: or endpointIds: unless you mean to read all of it, or use webhooks->iterateWorkspaceDeliveries to stop early.

المعلمات

endpointIdsstring|string[]

Endpoint ids to read, at most 50, as a list or one comma-separated string. Left out, every endpoint in the workspace.

statusstring

failed keeps only the attempts that did not get a 2xx, the "only failed" view of the app, and delivered keeps the rest.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size for each request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A list of delivery arrays holding every matching attempt, newest first.

مثال

$deliveries = $client->webhooks->listAllWorkspaceDeliveries(    endpointIds: ['whe_3f9c2a7b1e4d8f60a5c7b92d', 'whe_8a1c4e7b2d9f3a60c5e1b7d4'],    since: new \DateTimeImmutable('-1 day'),    limit: 100,); $perEndpoint = []; foreach ($deliveries as $delivery) {    $perEndpoint[$delivery['endpointId']] = ($perEndpoint[$delivery['endpointId']] ?? 0) + 1;} print_r($perEndpoint);

ملاحظات

  • If any page fails, the exception is thrown and the attempts already fetched are discarded.

متاح أيضًا في

API
GET /webhooks/deliveries
TypeScript
webhooks.listAllWorkspaceDeliveries()
Python
webhooks.list_all_workspace_deliveries()
Ruby
webhooks.list_all_workspace_deliveries

webhooks->iterateWorkspaceDeliveries

Stream the workspace's delivery attempts one at a time, newest first

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
iterateWorkspaceDeliveries(    array|string|null $endpointIds = null,    ?string $status = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Generator

Returns a Generator over webhooks->listWorkspaceDeliveries under the same filters. It fetches a page only when the one before is used up and stops requesting when you break out of the foreach.

المعلمات

endpointIdsstring|string[]

Endpoint ids to read, at most 50, as a list or one comma-separated string. Left out, every endpoint in the workspace.

statusstring

failed keeps only the attempts that did not get a 2xx, the "only failed" view of the app, and delivered keeps the rest.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size per request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A Generator that yields one delivery array per step.

مثال

foreach ($client->webhooks->iterateWorkspaceDeliveries(status: 'failed') as $delivery) {    echo 'Most recent failure: ', $delivery['endpointId'], ' ', $delivery['eventType'], ' at ', $delivery['createdAt'], PHP_EOL;     break;}

ملاحظات

  • The generator is lazy, so an abandoned loop costs only the pages you consumed.

متاح أيضًا في

API
GET /webhooks/deliveries
TypeScript
webhooks.iterateWorkspaceDeliveries()
Python
webhooks.iterate_workspace_deliveries()
Ruby
webhooks.iterate_workspace_deliveries

webhooks->listActivity

List one page of what happened to one endpoint

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listActivity(    string $id,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Page

Returns one page of an endpoint's audit log, newest first, the Activity tab of the endpoint in the app. Every change is a row: created, updated, enabled, disabled, auto_disabled, secret_rotated, tested, replayed and removed, whether it came from the app, from a key over the API, or from OpenEmail itself. actor says who, with label already formatted the way the app shows it: @username for a person, API key <name> for a key, and actor is null when OpenEmail made the change on its own, such as switching an endpoint off after 100 failed events in a row. detail carries what moved: the URL, previousUrl when it changed, the event types and allowlists an update set, or the status and response code a test or a replay got.

Nothing is pruned, and a removed endpoint keeps its history, so this answers for an endpoint that is gone too. since: and until: keep a window.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Rows per page, a whole number from 1 to 100. The server defaults to 25.

cursorstring

The nextCursor from the previous page, passed back unchanged. Never build one yourself.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

A Page of change arrays, with items, hasMore and nextCursor. Each item has id, endpointId, endpointLabel, type, createdAt, actor and detail.

مثال

$page = $client->webhooks->listActivity('whe_3f9c2a7b1e4d8f60a5c7b92d', since: new \DateTimeImmutable('-30 days')); foreach ($page as $change) {    echo $change['createdAt'], ' ', $change['type'], ' by ', $change['actor']['label'] ?? 'OpenEmail', PHP_EOL;}

ملاحظات

  • A 404 means no endpoint and no history with that id exists in this workspace. The cursor is opaque: pass nextCursor back as it came, and one this list did not hand out is a 400 invalid_cursor.

متاح أيضًا في

API
GET /webhooks/{id}/activity
TypeScript
webhooks.listActivity()
Python
webhooks.list_activity()
Ruby
webhooks.list_activity
CLI
openemail webhooks list-activity

webhooks->listAllActivity

Collect one endpoint's whole audit log into one array

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listAllActivity(    string $id,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): array

Walks every page of webhooks->listActivity under the same window and returns every change, newest first.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size for each request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A list of change arrays, newest first.

مثال

$changes = $client->webhooks->listAllActivity('whe_3f9c2a7b1e4d8f60a5c7b92d'); $rotations = array_filter($changes, static fn(array $change): bool => $change['type'] === 'secret_rotated'); echo count($changes), ' changes, ', count($rotations), ' of them secret rotations', PHP_EOL;

ملاحظات

  • If any page fails, the exception is thrown and the rows already fetched are discarded.

متاح أيضًا في

API
GET /webhooks/{id}/activity
TypeScript
webhooks.listAllActivity()
Python
webhooks.list_all_activity()
Ruby
webhooks.list_all_activity

webhooks->iterateActivity

Stream one endpoint's audit log one change at a time

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
iterateActivity(    string $id,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Generator

Returns a Generator over webhooks->listActivity under the same window, fetching a page only when the one before is used up.

المعلمات

idstringمطلوب

Endpoint id, whe_ followed by 24 hex characters.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size per request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A Generator that yields one change array per step.

مثال

foreach ($client->webhooks->iterateActivity('whe_3f9c2a7b1e4d8f60a5c7b92d') as $change) {    if ($change['type'] === 'auto_disabled') {        echo 'Switched off by OpenEmail at ', $change['createdAt'], PHP_EOL;         break;    }}

متاح أيضًا في

API
GET /webhooks/{id}/activity
TypeScript
webhooks.iterateActivity()
Python
webhooks.iterate_activity()
Ruby
webhooks.iterate_activity

webhooks->listWorkspaceActivity

List one page of what happened to every endpoint

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listWorkspaceActivity(    array|string|null $endpointIds = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Page

Returns one page of the whole workspace's webhook audit log, newest first, the Activity tab of Settings, Webhooks. Every change is a row: created, updated, enabled, disabled, auto_disabled, secret_rotated, tested, replayed and removed, whether it came from the app, from a key over the API, or from OpenEmail itself. actor says who, with label already formatted the way the app shows it: @username for a person, API key <name> for a key, and actor is null when OpenEmail made the change on its own, such as switching an endpoint off after 100 failed events in a row. detail carries what moved: the URL, previousUrl when it changed, the event types and allowlists an update set, or the status and response code a test or a replay got.

endpointIds: narrows it to some endpoints, removed ones included, and since: and until: keep a window.

المعلمات

endpointIdsstring|string[]

Endpoint ids to read, at most 50, as a list or one comma-separated string. Left out, every endpoint in the workspace.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Rows per page, a whole number from 1 to 100. The server defaults to 25.

cursorstring

The nextCursor from the previous page, passed back unchanged. Never build one yourself.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

A Page of change arrays, with items, hasMore and nextCursor. Each item has id, endpointId, endpointLabel, type, createdAt, actor and detail.

مثال

$page = $client->webhooks->listWorkspaceActivity(since: new \DateTimeImmutable('-7 days')); foreach ($page as $change) {    echo $change['endpointLabel'], ': ', $change['type'], ' by ', $change['actor']['label'] ?? 'OpenEmail', PHP_EOL;}

ملاحظات

  • The cursor is opaque: pass nextCursor back as it came. One this list did not hand out is a 400 invalid_cursor.

متاح أيضًا في

API
GET /webhooks/activity
TypeScript
webhooks.listWorkspaceActivity()
Python
webhooks.list_workspace_activity()
Ruby
webhooks.list_workspace_activity
CLI
openemail webhooks list-workspace-activity

webhooks->listAllWorkspaceActivity

Collect the whole webhook audit log into one array

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
listAllWorkspaceActivity(    array|string|null $endpointIds = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): array

Walks every page of webhooks->listWorkspaceActivity under the same filters and returns every change, newest first.

المعلمات

endpointIdsstring|string[]

Endpoint ids to read, at most 50, as a list or one comma-separated string. Left out, every endpoint in the workspace.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size for each request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A list of change arrays, newest first.

مثال

$changes = $client->webhooks->listAllWorkspaceActivity(since: new \DateTimeImmutable('-90 days'), limit: 100); $byKey = array_filter($changes, static fn(array $change): bool => ($change['actor']['kind'] ?? null) === 'apiKey'); echo count($changes), ' changes, ', count($byKey), ' of them made with an API key', PHP_EOL;

ملاحظات

  • If any page fails, the exception is thrown and the rows already fetched are discarded.

متاح أيضًا في

API
GET /webhooks/activity
TypeScript
webhooks.listAllWorkspaceActivity()
Python
webhooks.list_all_workspace_activity()
Ruby
webhooks.list_all_workspace_activity

webhooks->iterateWorkspaceActivity

Stream the whole webhook audit log one change at a time

الصلاحياتwebhooks:readيتصفح النتائج صفحةً صفحة
التوقيع
iterateWorkspaceActivity(    array|string|null $endpointIds = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?int $limit = null,    ?string $cursor = null,    ?string $apiKey = null,): Generator

Returns a Generator over webhooks->listWorkspaceActivity under the same filters, fetching a page only when the one before is used up.

المعلمات

endpointIdsstring|string[]

Endpoint ids to read, at most 50, as a list or one comma-separated string. Left out, every endpoint in the workspace.

sincestring|DateTimeInterface

Only rows at or after this instant. A DateTimeInterface is sent as ISO 8601, and a string must already be one.

untilstring|DateTimeInterface

Only rows before this instant. It has to be later than since:, or the server answers 400 invalid_parameter.

limitint

Page size per request, 1 to 100. The server defaults to 25.

cursorstring

Starts the walk from this cursor instead of the newest row.

apiKeystring

Overrides the client's API key for every page of this walk.

يُرجع

A Generator that yields one change array per step.

مثال

foreach ($client->webhooks->iterateWorkspaceActivity() as $change) {    if ($change['type'] === 'removed') {        echo $change['endpointLabel'], ' was removed by ', $change['actor']['label'] ?? 'OpenEmail', ' at ', $change['createdAt'], PHP_EOL;    }}

متاح أيضًا في

API
GET /webhooks/activity
TypeScript
webhooks.iterateWorkspaceActivity()
Python
webhooks.iterate_workspace_activity()
Ruby
webhooks.iterate_workspace_activity

webhooks->listEvents

List the events an endpoint can subscribe to

الصلاحياتwebhooks:read
التوقيع
listEvents(?string $apiKey = null): array

Returns every event an endpoint can name in eventTypes, each with a sentence saying when it fires, and the limits an endpoint is held to: how many endpoints the workspace may have, which its plan decides, and how many addresses and domains one allowlist may name.

An endpoint that names no events receives every email event except email.replied, so email.replied and the domain, suppression, file and form families only reach an endpoint that asks for them by name.

المعلمات

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array with events, a list of arrays with id and label, then maxEndpoints, maxAddresses and maxDomains.

مثال

$catalogue = $client->webhooks->listEvents(); foreach ($catalogue['events'] as $event) {    echo $event['id'], ': ', $event['label'], PHP_EOL;} echo 'Up to ', $catalogue['maxEndpoints'], ' endpoints, each naming up to ', $catalogue['maxAddresses'], ' addresses and ', $catalogue['maxDomains'], ' domains', PHP_EOL;

ملاحظات

  • The same events are the constants of OpenEmail\Constants\WebhookEvents, and WebhookEvents::values() lists their ids, so code that only needs the ids can skip the call.

  • Retried automatically on network failure, since it only reads.

متاح أيضًا في

API
GET /webhooks/events
TypeScript
webhooks.listEvents()
Python
webhooks.list_events()
Ruby
webhooks.list_events
CLI
openemail webhooks list-events

webhooks->stats

Read how webhook deliveries went inside a window

الصلاحياتwebhooks:read
التوقيع
stats(    array|string|null $endpointIds = null,    DateTimeInterface|string|null $since = null,    DateTimeInterface|string|null $until = null,    ?string $grain = null,    ?int $offsetMinutes = null,    ?string $apiKey = null,): array

Returns the numbers behind the Analytics tab of the Webhooks page: how many delivery attempts were made, how many were delivered and how many failed, the median time a receiver took to answer, a series of buckets, the events sent and the response codes received.

It covers every endpoint, or the ones endpointIds: names. Each try of an event counts as one attempt, so an event retried three times counts three times. The window runs from since: to until:, and left out it is the 30 days before now. grain: sets the bucket width and the key shape, YYYY-MM-DD, YYYY-MM-DDTHH or YYYY-MM-DDTHH:MM, and offsetMinutes: shifts the boundaries so days break where the reader's day does.

المعلمات

endpointIdsstring|string[]

Only these endpoints, at most 50, as a list or one comma-separated string. Left out, every endpoint.

sincestring|DateTimeInterface

The start of the window, a DateTimeInterface or an ISO 8601 instant. Defaults to 30 days before until:.

untilstring|DateTimeInterface

The end of the window, not included. Defaults to now.

grainstring

Bucket width: minute, hour or day, defaulting to day.

offsetMinutesint

Minutes east of UTC to bucket in, from -840 to 840, defaulting to 0. Pass intdiv((new DateTimeImmutable())->getOffset(), 60) for the local zone.

apiKeystring

Overrides the client's API key for this call only.

يُرجع

An array with the window it covered (since, until, grain and endpointIds), totals (attempts, delivered, failed and medianDurationMs), buckets, events and codes.

مثال

$stats = $client->webhooks->stats(    since: new \DateTimeImmutable('-7 days'),    grain: 'day',    offsetMinutes: intdiv((new \DateTimeImmutable())->getOffset(), 60),); $totals = $stats['totals']; echo $totals['delivered'], ' of ', $totals['attempts'], ' attempts delivered, median ', $totals['medianDurationMs'] ?? 'n/a', ' ms', PHP_EOL; foreach ($stats['codes'] as $code) {    echo $code['id'], ': ', $code['count'], PHP_EOL;}

ملاحظات

  • buckets is sparse: a bucket with no attempt has no entry, so a chart must fill the gaps.

  • medianDurationMs is null when nothing was sent in the window.

  • Retried automatically on network failure, since it only reads.

متاح أيضًا في

API
GET /webhooks/stats
TypeScript
webhooks.stats()
Python
webhooks.stats()
Ruby
webhooks.stats
CLI
openemail webhooks stats