API reference
Zeitwide API 1.0.0. Generated from the OpenAPI contract, so it always matches the API.
calendars
GET/v1/calendars
Every calendar, with its rules, revision and coverage
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| as_of | query | string (date-time) | Answer with what Zeitwide had recorded at this instant. Default now. |
- 200 The calendars in the dataset release. CalendarList
- 400 `validation_failed`: the request is malformed.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
- 503 `dataset_unavailable`: no dataset release has been cut yet.
GET/v1/calendars/{id}/days/{date}
Whether a date is a business day on one calendar, and why
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | CalendarId | |
| date * | path | string (date) | |
| as_of | query | string (date-time) | Answer with what Zeitwide had recorded at this instant. Default now. |
- 200 The answer and the entry or rule that decided it. DayAnswer
- 400 `validation_failed`: the request is malformed.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
- 404 `unknown_calendar`: no calendar has this ID.
- 422 `out_of_range`: a date is outside a calendar's source coverage.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
- 503 `dataset_unavailable`: no dataset release has been cut yet.
GET/v1/calendars/{id}/days
Answer every date in a range for one calendar
Each covered date from `from` to `to` (both inclusive, at most 500 days), answered as `GET /v1/calendars/{id}/days/{date}` would, with the nearest business days either side. Dates outside the calendar's coverage are left out. With no `from`, the range starts on 1 January of the current year; with no `to`, it ends 90 days after today. Both use the calendar's time zone, and `today` is the calendar's date now.
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | CalendarId | |
| from | query | string (date) | |
| to | query | string (date) | |
| as_of | query | string (date-time) | Answer with what Zeitwide had recorded at this instant. Default now. |
- 200 The covered days in the range, in date order. DayRange
- 400 `validation_failed`: the request is malformed.
- 404 `unknown_calendar`: no calendar has this ID.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
- 503 `dataset_unavailable`: no dataset release has been cut yet.
GET/v1/calendars/{id}/closures
The closures on one calendar between two dates
Closures are the dates an entry closes (weekends aren't listed). The range is at most 731 days, and all of it must be within the calendar's coverage.
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | CalendarId | |
| from * | query | string (date) | |
| to * | query | string (date) | Inclusive; on or after `from`. |
| as_of | query | string (date-time) | Answer with what Zeitwide had recorded at this instant. Default now. |
- 200 The closures in date order. ClosureList
- 400 `validation_failed`: the request is malformed.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
- 404 `unknown_calendar`: no calendar has this ID.
- 422 `out_of_range`: a date is outside a calendar's source coverage.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
- 503 `dataset_unavailable`: no dataset release has been cut yet.
business days
POST/v1/business-days/check
Whether a date is a business day on several calendars combined
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| as_of | query | string (date-time) | Answer with what Zeitwide had recorded at this instant. Default now. |
Body: DayRequest
- 200 The combined answer, with each calendar's answer as evidence. DayAnswer
- 400 `validation_failed`: the request is malformed.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
- 404 `unknown_calendar`: no calendar has this ID.
- 422 `out_of_range`: a date is outside a calendar's source coverage.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
- 503 `dataset_unavailable`: no dataset release has been cut yet.
POST/v1/business-days/add
Move a number of business days from a date
Moves `days` business days from `date`, backwards when negative. `date` itself doesn't count, and 0 returns `date`. Every day passed over is listed in `skipped`, in the order met, with why it isn't a business day.
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| as_of | query | string (date-time) | Answer with what Zeitwide had recorded at this instant. Default now. |
Body: AddRequest
- 200 Where the move landed. Shifted
- 400 `validation_failed`: the request is malformed.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
- 404 `unknown_calendar`: no calendar has this ID.
- 422 `out_of_range`: a date is outside a calendar's source coverage.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
- 503 `dataset_unavailable`: no dataset release has been cut yet.
POST/v1/business-days/next
The first business day after a date
Never `date` itself; the same as adding one business day.
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| as_of | query | string (date-time) | Answer with what Zeitwide had recorded at this instant. Default now. |
Body: DayRequest
- 200 The next business day. Shifted
- 400 `validation_failed`: the request is malformed.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
- 404 `unknown_calendar`: no calendar has this ID.
- 422 `out_of_range`: a date is outside a calendar's source coverage.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
- 503 `dataset_unavailable`: no dataset release has been cut yet.
changes
GET/v1/changes
List published calendar changes using keyset pagination
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| calendars | query | array of CalendarId | Up to 10 calendar IDs; omit to include all calendars. |
| since * | query | string (date-time) | |
| types | query | array of ChangeType | Change types to include; omit to include all types. |
| cursor | query | string | |
| limit | query | integer |
- 200 Changes ordered by publication instant and stable event ID. ChangePage
- 400 `validation_failed`: the request is malformed.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
receipts
POST/v1/receipts/verify
Verify a receipt against the configured public key history
Needs a Keycloak token or an API key.
Body: Receipt
- 200 `valid` is false for a modified payload, signature, ID or unknown key. ReceiptVerification
- 400 `validation_failed`: the request is malformed.
GET/.well-known/zeitwide-keys.json
Public Ed25519 verification keys and validity intervals
Open to anyone, no key needed.
- 200 Current and retained historical public keys. ReceiptKeySet
mcp
GET/.well-known/oauth-protected-resource/mcp
OAuth protected resource metadata for the MCP endpoint
Open to anyone, no key needed.
- 200 MCP resource identifier, authorization server, and supported bearer method. object
account
GET/v1/account/api-keys
List API keys for the authenticated account
Needs a Keycloak token or an API key.
- 200 Up to 100 key metadata rows. Secret values are never returned by this operation. array of ApiKeySummary
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
POST/v1/account/api-keys
Create an API key and return its value once
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| Idempotency-Key * | header | string | A 16–128 character key. Reuse is rejected so a retry cannot create another secret. |
Body: object
- 201 The key value is present only in this response. CreatedApiKey
- 400 `validation_failed`: the request is malformed.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
- 409 API key account limit reached or this idempotency key was already used.
DELETE/v1/account/api-keys/{id}
Revoke one API key belonging to the authenticated account
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | string (uuid) |
- 204 The key was revoked or was already absent.
- 401 `invalid_api_key`: the key is unknown, malformed or revoked.
GET/v1/account/webhooks
List webhook subscriptions without their signing secrets
Needs a Keycloak token or an API key.
- 200 Up to 100 active subscriptions for the authenticated account. array of WebhookSubscription
- 401 `unauthorized`: authentication is required.
POST/v1/account/webhooks
Create a webhook and return its signing secret once
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| Idempotency-Key * | header | string |
Body: WebhookConfiguration
- 201 The generated signing secret is returned only in this response. CreatedWebhook
- 400 `validation_failed`: the request is malformed.
- 401 `unauthorized`: authentication is required.
- 409 `idempotency_key_reused`: this key was already used.
- 429 `rate_limited`: too many requests; try again after `Retry-After` seconds.
PUT/v1/account/webhooks/{id}
Update a webhook URL and event filter
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | string (uuid) |
Body: WebhookConfiguration
- 200 The updated subscription; its signing secret remains hidden. WebhookSubscription
- 400 `validation_failed`: the request is malformed.
- 404 `not_found`: no active resource has this ID.
DELETE/v1/account/webhooks/{id}
Disable a webhook and abandon its pending deliveries
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | string (uuid) |
- 204 The subscription was disabled or was already absent.
POST/v1/account/webhooks/{id}/test
Send a signed test event to a webhook
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | string (uuid) |
- 200 Test event delivery result; receiver response bodies are discarded. WebhookTestResult
- 404 `not_found`: no active resource has this ID.
GET/v1/account/alert-rules
List the account's alert rules
Alert rules say which published changes matter to the account. While an account has at least one rule, its webhooks receive only changes that match a rule (and the webhook's own event filter); with no rules, webhooks receive every change.
Needs a Keycloak token or an API key.
- 200 Up to 50 rules, newest first. array of AlertRule
- 401 `unauthorized`: authentication is required.
POST/v1/account/alert-rules
Create an alert rule
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| Idempotency-Key * | header | string |
Body: AlertRuleConfiguration
- 201 The created rule. AlertRule
- 400 `validation_failed`: the request is malformed.
- 401 `unauthorized`: authentication is required.
- 409 `alert_rule_limit_reached` or `idempotency_key_reused`.
PUT/v1/account/alert-rules/{id}
Replace an alert rule
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | string (uuid) |
Body: AlertRuleConfiguration
- 200 The updated rule. AlertRule
- 400 `validation_failed`: the request is malformed.
- 404 `not_found`: no active resource has this ID.
DELETE/v1/account/alert-rules/{id}
Delete an alert rule
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | string (uuid) |
- 204 The rule was deleted or was already absent.
admin
GET/v1/admin/candidates
List candidate changes for review, urgent first
Pending candidates sort urgent first (under 14 days' notice), then by date. Requires the Keycloak role `reviewer`.
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| status | query | CandidateStatus | |
| limit | query | integer |
- 200 Candidates with the requested status. CandidateList
- 401 `unauthorized`: authentication is required.
- 403 `forbidden`: the caller lacks the required role.
GET/v1/admin/candidates/{id}
One candidate with the current entry and every supporting snapshot
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | integer (int64) |
- 200 The candidate and its evidence. CandidateDetail
- 401 `unauthorized`: authentication is required.
- 403 `forbidden`: the caller lacks the required role.
- 404 `not_found`: no active resource has this ID.
POST/v1/admin/candidates/{id}/decision
Approve or reject a pending candidate
Records the reviewer (the token's subject), the reason and the time. The pipeline publishes an approved candidate on its next run, in one transaction; no answer changes before then.
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| id * | path | integer (int64) |
Body: CandidateDecision
- 200 The candidate after the decision. CandidateDetail
- 400 `validation_failed`: the request is malformed.
- 401 `unauthorized`: authentication is required.
- 403 `forbidden`: the caller lacks the required role.
- 404 `not_found`: no active resource has this ID.
- 409 `candidate_not_pending`: someone already decided this candidate.
GET/v1/admin/sources
Freshness and failures for every source
Needs a Keycloak token or an API key.
- 200 Every source with its check state. SourceHealthList
- 401 `unauthorized`: authentication is required.
- 403 `forbidden`: the caller lacks the required role.
GET/v1/admin/releases
Dataset releases, newest first
Needs a Keycloak token or an API key.
| Parameter | In | Type | Notes |
|---|---|---|---|
| limit | query | integer |
- 200 The most recent releases. ReleaseList
- 401 `unauthorized`: authentication is required.
- 403 `forbidden`: the caller lacks the required role.
Schemas
AddRequest
| Field | Type | Notes |
|---|---|---|
| calendars * | array of CalendarId | |
| date * | string (date) | |
| days * | integer | |
| combine | Combine | |
| as_of | string (date-time) |
AlertRule
| Field | Type | Notes |
|---|---|---|
| id * | string (uuid) | |
| name * | string | |
| calendars * | array of CalendarId | |
| events * | array of ChangeType | |
| max_notice_days * | integer or null | |
| created_at * | string (date-time) |
AlertRuleConfiguration
| Field | Type | Notes |
|---|---|---|
| name * | string | |
| calendars * | array of CalendarId | |
| events * | array of ChangeType | |
| max_notice_days | integer or null | Only changes announced this many days or fewer ahead; null for any notice. |
ApiKeySummary
| Field | Type | Notes |
|---|---|---|
| id * | string (uuid) | |
| name * | string | |
| prefix * | string | |
| created_at * | string (date-time) | |
| last_used_at | string or null (date-time) | |
| revoked_at | string or null (date-time) |
Basis
`published` by the operator, or `projected` by Zeitwide from other sources.
published | projected
Calendar
| Field | Type | Notes |
|---|---|---|
| id * | CalendarId | |
| name * | string | |
| kind * | rail | public | exchange | |
| timezone * | string | |
| weekend * | array of monday | tuesday | wednesday | thursday | friday | saturday | sunday | |
| closes_on_holidays * | boolean | |
| revision * | integer | |
| coverage * | Coverage |
CalendarDay
One calendar's answer for one date, and what decided it.
| Field | Type | Notes |
|---|---|---|
| calendar_id * | CalendarId | |
| is_open * | boolean | |
| decided_by * | entry | weekend_rule | An entry (with its reason, basis and sources), or the weekend rule. |
| reason | string | Only when an entry decided. |
| basis | Basis | |
| revision | integer | The calendar revision that published the entry. |
| recorded_from | string (date-time) | |
| sources * | array of Source |
CalendarId
string
CalendarList
| Field | Type | Notes |
|---|---|---|
| calendars * | array of Calendar | |
| as_of * | string (date-time) | |
| dataset_release * | DatasetRelease | |
| calendar_revisions * | CalendarRevisions | |
| receipt * | Receipt |
CalendarRevisions
Each calendar's revision at `as_of`, by calendar ID.
object
Candidate
| Field | Type | Notes |
|---|---|---|
| id * | integer (int64) | |
| calendar_id * | CalendarId | |
| entry_date * | string (date) | |
| before * | EntryState or null | The published state when the candidate was opened; null for a new date. |
| after * | EntryState | |
| corroboration * | Corroboration | |
| source_count * | integer | |
| notice_days * | integer | Days from today (UTC) to the date; negative once it has passed. |
| urgent * | boolean | Under 14 days' notice. |
| status * | CandidateStatus | |
| created_at * | string (date-time) |
CandidateDecision
| Field | Type | Notes |
|---|---|---|
| decision * | approve | reject | |
| reason * | string |
CandidateDetail
| Field | Type | Notes |
|---|---|---|
| candidate * | Candidate | |
| current * | EntryState or null | The entry published now, if any. |
| snapshots * | array of CandidateSnapshot | |
| reviewer * | string or null | |
| review_reason * | string or null | |
| reviewed_at * | string or null (date-time) |
CandidateList
| Field | Type | Notes |
|---|---|---|
| candidates * | array of Candidate |
CandidateSnapshot
One source snapshot that supports the candidate, and what the parser read from it.
| Field | Type | Notes |
|---|---|---|
| source * | string | The source's slug. |
| publisher * | string | |
| url * | string (uri) | |
| role * | primary | corroborating | |
| fetched_at * | string (date-time) | |
| snapshot_sha256 * | string | |
| http_status * | integer | |
| content_type * | string or null | |
| byte_size * | integer | |
| is_open * | boolean | |
| reason * | string | |
| parser_version * | string |
CandidateStatus
pending | approved | rejected | published
Change
| Field | Type | Notes |
|---|---|---|
| id * | integer (int64) | |
| type * | ChangeType | |
| calendar_id * | CalendarId | |
| entry_date * | string (date) | |
| before | object or null | |
| after * | object | |
| notice_days * | integer | |
| published_at * | string (date-time) |
ChangePage
| Field | Type | Notes |
|---|---|---|
| changes * | array of Change | |
| next_cursor * | string or null | |
| since * | string (date-time) | |
| limit * | integer |
ChangeType
closure_added | closure_removed | closure_changed | basis_changed
Closure
| Field | Type | Notes |
|---|---|---|
| date * | string (date) | |
| reason * | string | |
| basis * | Basis | |
| revision * | integer | |
| recorded_from * | string (date-time) | |
| sources * | array of Source |
ClosureList
| Field | Type | Notes |
|---|---|---|
| calendar_id * | CalendarId | |
| from * | string (date) | |
| to * | string (date) | |
| closures * | array of Closure | |
| as_of * | string (date-time) | |
| dataset_release * | DatasetRelease | |
| calendar_revision * | integer | |
| calendar_revisions * | CalendarRevisions | |
| receipt * | Receipt |
Combine
`all_open`: every calendar is open. `any_open`: at least one is.
all_open | any_open
Corroboration
`corroborated`: a second, independent source agrees.
single_source | corroborated
Coverage
The dates the calendar can answer for. `years`: from `from` to `to`, both inclusive. `unlimited`: any date (the calendar closes on no holiday). `none`: nothing recorded yet, so no date.
| Field | Type | Notes |
|---|---|---|
| type * | years | unlimited | none | |
| from | string (date) | Only for `years`. |
| to | string (date) | Only for `years`. |
CreatedApiKey
| Field | Type | Notes |
|---|---|---|
| id * | string (uuid) | |
| name * | string | |
| prefix * | string | |
| key * | string | |
| created_at * | string (date-time) |
CreatedWebhook
WebhookSubscription and object
DatasetRelease
string
DayAnswer
| Field | Type | Notes |
|---|---|---|
| date * | string (date) | |
| is_business_day * | boolean | |
| combine * | Combine | |
| calendars * | array of CalendarDay | |
| as_of * | string (date-time) | |
| dataset_release * | DatasetRelease | |
| calendar_revisions * | CalendarRevisions | |
| receipt * | Receipt |
DayRange
| Field | Type | Notes |
|---|---|---|
| calendar_id * | CalendarId | |
| today * | string (date) | The calendar's date now |
| from * | string (date) | |
| to * | string (date) | |
| days * | array of RangeDay | |
| as_of * | string (date-time) | |
| dataset_release * | DatasetRelease | |
| calendar_revisions * | CalendarRevisions | |
| receipt * | Receipt |
DayRequest
| Field | Type | Notes |
|---|---|---|
| calendars * | array of CalendarId | |
| date * | string (date) | |
| combine | Combine | |
| as_of | string (date-time) |
EntryState
| Field | Type | Notes |
|---|---|---|
| is_open * | boolean | |
| reason * | string | |
| basis | Basis |
OutboxDrainResult
| Field | Type | Notes |
|---|---|---|
| outbox_events * | integer | |
| claimed * | integer | |
| succeeded * | integer | |
| retried * | integer | |
| failed * | integer |
Problem
RFC 9457 problem details.
| Field | Type | Notes |
|---|---|---|
| type | string (uri-reference) | |
| title * | string | |
| status * | integer | |
| detail | string | |
| instance | string (uri-reference) | |
| code * | validation_failed | invalid_api_key | unauthorized | forbidden | length_required | payload_too_large | api_key_limit_reached | idempotency_key_reused | webhook_limit_reached | alert_rule_limit_reached | candidate_not_pending | unknown_calendar | out_of_range | rate_limited | dataset_unavailable | not_found | internal_error |
RangeDay
| Field | Type | Notes |
|---|---|---|
| date * | string (date) | |
| is_open * | boolean | |
| decided_by * | entry | weekend_rule | |
| reason | string | Only when an entry decided. |
| basis | Basis | |
| sources * | array of Source | The snapshots behind the entry; empty when the weekend rule decided. |
| next_business_day | string (date) | The first business day after `date`; absent if it is past coverage. |
| previous_business_day | string (date) | The last business day before `date`; absent if it is before coverage. |
Receipt
| Field | Type | Notes |
|---|---|---|
| id * | string | |
| payload * | ReceiptPayload | |
| payload_hash * | string | |
| key_id * | string | |
| signature * | string |
ReceiptKeySet
| Field | Type | Notes |
|---|---|---|
| keys * | array of ReceiptPublicKey |
ReceiptPayload
| Field | Type | Notes |
|---|---|---|
| request * | object | |
| answer * | object | |
| dataset_release * | DatasetRelease | |
| calendar_revisions * | CalendarRevisions | |
| issued_at * | string (date-time) |
ReceiptPublicKey
| Field | Type | Notes |
|---|---|---|
| key_id * | string | |
| public_key * | string | PEM-encoded Ed25519 SubjectPublicKeyInfo. |
| valid_from * | string (date-time) | |
| valid_to * | string or null (date-time) |
ReceiptVerification
| Field | Type | Notes |
|---|---|---|
| valid * | boolean |
Release
| Field | Type | Notes |
|---|---|---|
| id * | DatasetRelease | |
| as_of * | string (date-time) | |
| calendar_revisions * | CalendarRevisions | |
| export_sha256 * | string | |
| created_at * | string (date-time) |
ReleaseList
| Field | Type | Notes |
|---|---|---|
| releases * | array of Release |
Shifted
| Field | Type | Notes |
|---|---|---|
| start * | string (date) | |
| days * | integer | |
| date * | string (date) | Where the move landed. |
| combine * | Combine | |
| calendars * | array of CalendarDay | Each calendar's answer for `date`. |
| skipped * | array of SkippedDay | Days passed over because they weren't business days, in the order met. |
| as_of * | string (date-time) | |
| dataset_release * | DatasetRelease | |
| calendar_revisions * | CalendarRevisions | |
| receipt * | Receipt |
SkippedDay
| Field | Type | Notes |
|---|---|---|
| date * | string (date) | |
| calendars * | array of CalendarDay |
Source
A snapshot of an official source that backs an entry.
| Field | Type | Notes |
|---|---|---|
| publisher * | string | |
| url * | string (uri) | |
| retrieved_at * | string (date-time) | |
| snapshot_sha256 * | string |
SourceHealth
| Field | Type | Notes |
|---|---|---|
| source * | string | |
| publisher * | string | |
| url * | string (uri) | |
| role * | primary | corroborating | |
| schedule * | string | |
| enabled * | boolean | |
| health * | healthy | failing | suspended | disabled | never_checked | `failing`: the last check failed; `suspended`: stopped after repeated failures. |
| consecutive_failures * | integer | |
| last_checked_at * | string or null (date-time) | |
| last_success_at * | string or null (date-time) | |
| last_snapshot_at * | string or null (date-time) | |
| last_snapshot_sha256 * | string or null | |
| last_error * | string or null | |
| suspended_at * | string or null (date-time) |
SourceHealthList
| Field | Type | Notes |
|---|---|---|
| sources * | array of SourceHealth |
WebhookConfiguration
| Field | Type | Notes |
|---|---|---|
| url * | string (uri) | HTTPS URL on a public host using port 443. |
| events * | array of ChangeType |
WebhookSubscription
| Field | Type | Notes |
|---|---|---|
| id * | string (uuid) | |
| url * | string (uri) | |
| events * | array of ChangeType | |
| created_at * | string (date-time) |
WebhookTestResult
| Field | Type | Notes |
|---|---|---|
| succeeded * | boolean | |
| response_status * | integer or null |