Safe Creative Platform

API reference

Safe Creative Platform API · version 1.0-draft · Try the API in the playground

Generated automatically from the OpenAPI contract of the API. openapi.yaml

Event registration with qualified-trust evidence, operated by Safe Creative as an independent trusted third party.

What the service certifies: that a declaration was received, exactly when, and that it has not been altered since — never the truth of the declared fact.

Base URL: https://platform.safecreative.org/v1.

Modes: every API key is either live (sc_live_…) or test (sc_test_…). Test keys hit the same endpoints with the same contract, consume no balance, produce no probative value, and write to a separate per-channel chain. Test mode has daily limits per account (UTC): 10,000 events, 100 MB of declared content and 20 certifications, each of at most 10,000 events; past a daily limit the API answers 429 test_quota_exceeded with Retry-After until the next day.

Conventions

  • Rate limits per API key: 50 req/s sustained for live keys (bursts ×4; an account may have its own limit), 10 req/s for test keys. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds); a 429 rate_limited adds Retry-After.
  • Temporary unavailability: an event is only acknowledged once it is durably stored and replicated. During a transient storage failure any operation may answer 503 temporarily_unavailable with Retry-After: retry, with the same client_ref when registering events.
  • Language: error message in English by default, Spanish with Accept-Language: es.
  • Forced test scenarios: with a test key, X-SC-Test-Scenario: unpaid | unpaid_limit | rate_limited reproduces the documented 402/429 responses without touching real state.
  • Webhook signature: see WebhookEnvelope.

Formats

  • Timestamps in responses and webhooks are UTC, RFC 3339 with the Z suffix and exactly six fractional digits (microseconds, the precision they are stored with), e.g. 2026-09-28T07:00:16.526317Z. The acknowledgment of POST /events returns received_at exactly as it is registered and later certified.
  • Timestamps in requests (occurred_at, certification ranges, query filters) accept any RFC 3339 date-time with an offset (Z or ±hh:mm) and up to nine fractional digits; they are normalized to UTC and truncated to microseconds.
  • Hashes are lowercase hexadecimal. Credits and sequence numbers are integers.

Operations

Webhooks

POST /events Declare (register) an event Try it

Registers one declared event on the channel identified by the API key. The synchronous acknowledgment is the client's receipt: it commits the event's position in the channel sequence.

Idempotency: client_ref must be unique per channel. Retrying with the same client_ref and identical content returns 200 with the original event; same client_ref with different content returns 409 and never overwrites.

Exhausted balance: events are still registered, sealed and chained with status: unpaid, up to the back-office unpaid limit; past it, 402 unpaid_limit_exceeded.

Body

Responses

201Event registered (new).Event
200Idempotent replay — same client_ref, identical content; original event returned.Event
400Invalid body or parameters, or modality mismatch (validation_error).Error
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
402Unpaid-events limit reached (unpaid_limit_exceeded).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
409client_ref already used on this channel with different content (client_ref_conflict).Error
413Body over the modality limit (payload_too_large).Error
422Blocked by a user-defined consumption limit set to "block" (limit_blocked).Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error
503Temporarily unavailable (temporarily_unavailable): a transient storage failure, e.g. during a database failover. Nothing was acknowledged: retry after Retry-After with the same client_ref, which idempotency resolves.Error

GET /events List events of the channel Try it

Parameters

fromqueryReceived-at lower bound (inclusive). RFC 3339 date-time with an offset (Z or ±hh:mm); normalized to UTC and truncated to microseconds (see Formats).
toqueryReceived-at upper bound (exclusive). RFC 3339 date-time with an offset (Z or ±hh:mm); normalized to UTC and truncated to microseconds (see Formats).
seq_fromquery
seq_toquery
statusquery
limitquery
cursorqueryOpaque pagination cursor.

Responses

200Paginated event list, ordered by sequence.application/json
400Invalid body or parameters, or modality mismatch (validation_error).Error
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error

GET /events/{event_id} Get one event with its full proof elements Try it

Parameters

event_idpath · required

Responses

200The event.Event
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
404Resource not found on this channel (not_found).Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error

GET /events/{event_id}/content Download the content held for an event Try it

Content modality only (modality: content): returns the declared content exactly as Safe Creative holds it — the JSON in its canonical form, the one that was hashed, or the file, with its original name in Content-Disposition. Its digest is the event's hash. A hash-only event has no content: 404 not_found.

Parameters

event_idpath · required

Responses

200The content — application/json for JSON content, application/octet-stream for a file.application/json | application/octet-stream
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
404Resource not found on this channel (not_found).Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error

GET /channel Get the channel and its sealed configuration versions Try it

Responses

200Channel with current configuration and version history.Channel
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error

GET /account/balance Balance and operational status of the channel's owner account Try it

Lets client systems self-monitor (low balance, unpaid events, operational status).

Responses

200Balance snapshot.AccountBalance
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error

POST /certifications Request a certification of a range (asynchronous) Try it

Starts the issuance of the signed certification reports (one in Spanish and one in English) plus their evidence archive for a range of this channel, by dates or by sequence numbers.

Rejected with 402 account_not_operational while the owner account has any unpaid event ("cuenta sin saldo operativo").

Body

Responses

202Accepted; issuance runs asynchronously.Certification
400Invalid body or parameters, or modality mismatch (validation_error).Error
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
402account_not_operational (unpaid events or negative balance) or insufficient_balance (issuance fee, if enabled).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error
503Temporarily unavailable (temporarily_unavailable): a transient storage failure, e.g. during a database failover. Nothing was acknowledged: retry after Retry-After with the same client_ref, which idempotency resolves.Error

GET /certifications List certifications of the channel Try it

Parameters

statusquery
limitquery
cursorquery

Responses

200Paginated list, newest first.application/json
400Invalid body or parameters, or modality mismatch (validation_error).Error
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error

GET /certifications/{certification_id} Get a certification's status and download links Try it

Parameters

certification_idpath · required

Responses

200The certification. When completed, includes download URLs (report PDFs and evidence ZIP; URLs expire after 7 days and can be regenerated by re-fetching) and the public verification code.Certification
401Missing, invalid or revoked key (invalid_key / revoked_key).Error
403Channel or owner account suspended by Safe Creative (suspended: event registration and certifications are rejected), or owner account disabled (account_disabled: every call is rejected; accounts are disabled after a year without registering events, requesting certifications or buying credits, and support reactivates them). Data and chains are untouched.Error
404Resource not found on this channel (not_found).Error
429Rate limit exceeded (rate_limited) or, with a test key, a test-mode daily limit reached (test_quota_exceeded); includes Retry-After.Error

Webhooks

Notices the platform POSTs to the endpoints you configure in the console. They all share the envelope WebhookEnvelope.

POST certification.completed A requested certification finished successfully.

The certification is completed: the reports, the evidence ZIP and the verification code are ready. data.verification_code is present; fetch GET /certifications/{certification_id} for fresh download URLs. mode is the certification's mode.

data: WebhookCertificationData

POST certification.failed A requested certification failed (includes an incident id).

The certification could not be issued (status: failed): any issuance charge is refunded and data.incident_id identifies the incident for support. The same range can be requested again. mode is the certification's mode.

data: WebhookCertificationData

POST balance.low Balance crossed a user-defined threshold downwards.

Sent once per downward crossing of each alert threshold set in the console; the threshold re-arms when a purchase or an adjustment takes the balance back above it. Always live.

data: WebhookBalanceLowData

POST balance.exhausted First unpaid event registered (balance reached zero).

The balance ran out and an event was registered as unpaid (it is still sealed and chained). From now on certifications are rejected with 402 account_not_operational until a purchase settles the unpaid events. Sent once per exhaustion. Always live.

data: WebhookBalanceExhaustedData

POST events.unpaid_limit_reached Unpaid-events limit reached; registrations are now being rejected.

The account reached its unpaid-events limit: from now on POST /events answers 402 unpaid_limit_exceeded until a purchase settles the debt. Always live.

data: WebhookUnpaidLimitData

POST consumption.limit_reached A user-defined consumption limit was reached.

A consumption limit set in the console (per channel or per key, daily or monthly in UTC) reached its maximum. With action block further registrations answer 422 limit_blocked until the next period; with warn they keep going through. Sent once per limit and period. Test events do not count. Always live.

data: WebhookConsumptionLimitData

POST recharge.auto_completed An automatic top-up was charged and its credits added.

The balance dropped below the automatic top-up threshold set in the console and the chosen pack was bought with the default payment method at Safe Creative; its credits are already in the balance (after settling any unpaid events). Safe Creative sends the invoice. Always live.

data: WebhookAutoRechargeData

POST recharge.auto_failed An automatic top-up failed; automatic top-up has been turned off.

The automatic top-up could not be made (data.reason) and has been turned off, keeping its settings: it can be turned back on in the console. If the purchase was created but not charged, data.payment_url lets the owner pay it manually. Always live.

data: WebhookAutoRechargeData

POST webhook.test Test delivery requested from the console.

Only sent when the account owner asks for a test delivery of an endpoint from the console: a single attempt, no retries, and it never counts towards disabling the endpoint. Always live.

data: WebhookTestData

Schemas

NewEventContent

Content modality — JSON token generated by the client's process.

FieldType
client_ref *stringUnique event id in the emitting system (idempotency key per channel).
payload *objectThe declared content (JSON). Max body size 256 KB.
occurred_atstring (date-time)When the emitter declares the fact happened. Part of the declaration — Safe Creative proves the reception time, not this value. RFC 3339 date-time with an offset (Z or ±hh:mm); normalized to UTC and truncated to microseconds (see Formats).

NewEventHashOnly

Hash-only modality — the content never leaves the client's perimeter.

FieldType
client_ref *string
hash *stringHex-encoded digest of the client-held content.
hash_alg *string: sha-256 · sha-512
occurred_atstring (date-time)When the emitter declares the fact happened. RFC 3339 date-time with an offset (Z or ±hh:mm); normalized to UTC and truncated to microseconds (see Formats).

NewEventFile

Content modality — file attachment. Max 10 MB.

FieldType
client_ref *string
file *string (binary)
occurred_atstring (date-time)When the emitter declares the fact happened. RFC 3339 date-time with an offset (Z or ±hh:mm); normalized to UTC and truncated to microseconds (see Formats).

Event

FieldType
event_id *string
channel_id *string
client_ref *string
sequence *integerStrictly increasing, gapless, per channel (per chain in test mode).
received_at *string (date-time)Service reception time — the time the evidence attests. UTC, microseconds (see Formats).
occurred_atstring | null (date-time)Declared by the emitter; not attested by Safe Creative. Returned in UTC, microseconds (see Formats).
hash *stringDigest of the content (or the client-declared digest in hash-only modality).
hash_algstring
modality *string: content · hash_onlycontent = Safe Creative holds the declared JSON or file, downloadable with GET /events/{event_id}/content; hash_only = only the digest was declared.
chain_hash *stringChained digest binding this event to the previous one on the channel.
status *string: registered · unpaid · testunpaid = registered & sealed but pending payment; blocks certifications account-wide.
timestampEventTimestampQualified-timestamp coverage of this event.
config_version *integerChannel configuration version in force at reception.
mode *string: live · test

EventTimestamp

Qualified-timestamp coverage of an event (Event.timestamp).

FieldType
type *string: individual · batch · pending · simulatedbatch = proven by inclusion in a sealed chain segment of the channel (the sealing policy in use); pending = within the sealing window; simulated = test mode. individual = own qualified timestamp: reserved, not produced today (every live event is proven by its channel's sealed segment); kept so that individual sealing can be offered without breaking the contract. Clients should accept it.
referencestring | nullTimestamp or sealed-segment reference once consolidated (seg_… for a sealed segment).
sealed_atstring | null (date-time)When the covering timestamp was obtained. UTC, microseconds (see Formats).

Channel

FieldType
channel_id *string
name *string
mode_note *stringReminder that live and test chains are separate.
current_config *ChannelConfig
config_versions *ChannelConfig[]

ChannelConfig

A sealed, immutable configuration version. Changes create new versions; none is rewritten.

FieldType
version *integer
sealed_at *string (date-time)When this configuration version was sealed (pre-commitment to the facts). UTC, microseconds (see Formats).
modality *string: content · hash_only
namestring
descriptionstring
declarant *stringPerson or entity on whose behalf events are declared and certifications are requested. Presented in reports as a declaration of the channel owner — not verified by Safe Creative.
supplementary_infostring | nullOptional client text explaining what the declared data means.

NewCertification

Range by dates or by sequence numbers (exactly one pair).

FieldType
fromstring (date-time)Start of the reception range, inclusive. RFC 3339 date-time with an offset (Z or ±hh:mm); normalized to UTC and truncated to microseconds (see Formats).
tostring (date-time)End of the reception range, exclusive; a future value is cut at the moment of the request. RFC 3339 date-time with an offset (Z or ±hh:mm); normalized to UTC and truncated to microseconds (see Formats).
seq_fromintegerFirst sequence number, inclusive.
seq_tointegerLast sequence number, inclusive.

Certification

FieldType
certification_id *string
channel_id *string
status *string: processing · completed · failed
progressnumber | nullApproximate progress (0–1) while processing.
requested_at *string (date-time)When the request was accepted. UTC, microseconds (see Formats).
completed_atstring | null (date-time)When the certification was issued (the issue date printed on the reports) or failed. UTC (see Formats).
range *CertificationRangeThe range as requested. It is resolved and frozen on acceptance into sequence numbers of the chain.
event_countinteger | null
config_versions_in_rangeinteger[]
report_urlstring | nullDownload of the signed PDF report in the language of the request (Accept-Language: Spanish or English, English by default); expiring URL. reports lists both languages.
reportsCertificationReport[]The signed PDF reports: one in Spanish and one in English, signed separately, with the same verification code and the same evidence archive. Both are equally authentic and each can be verified on its own. Earlier certifications may have a single bilingual report (languages: [es, en]). Empty while processing.
evidence_urlstring | nullEvidence ZIP download (expiring URL).
verification_codestring | nullCode for the public verification page.
mode *string: live · test
content_partsContentPart[]Content modality: the declared content, in ZIP parts of up to 1 GB that are listed with their SHA-256 in the evidence manifest and in the reports (expiring URLs, like report_url). Empty for hash-only channels and while processing.

CertificationReport

One signed PDF report of a certification (Certification.reports).

FieldType
languages *string[]Language of the report, [es] or [en]; both in the bilingual report of earlier certifications.
url *stringDownload URL (expiring, like report_url).
sha256 *stringSHA-256 of the signed PDF, lowercase hex; the public verification page recognizes it.

CertificationRange

Range of a certification (Certification.range), as requested: exactly one pair is set, the reception dates (from, to) or the sequence numbers (seq_from, seq_to); the other pair is null.

FieldType
fromstring | null (date-time)Start of the reception range, inclusive. UTC, microseconds (see Formats).
tostring | null (date-time)End of the reception range, exclusive; a future to is cut at the moment of the request. UTC, microseconds.
seq_frominteger | nullFirst sequence number, inclusive.
seq_tointeger | nullLast sequence number, inclusive.

ContentPart

One ZIP part of the declared content of a certification (Certification.content_parts).

FieldType
name *stringFile name, content-part-NNN.zip.
url *stringDownload URL (expiring, like report_url).
sha256 *stringSHA-256 of the part, lowercase hex; also listed in the evidence manifest and in the reports.
bytes *integerSize of the part in bytes.

AccountBalance

Balance in credits. One live event consumes one credit; credits are bought in packs in the console, priced per region and currency. The balance itself has no currency.

FieldType
balance *integerAvailable credits. Negative only if a purchase is reverted after its credits were spent.
operational *booleanfalse while the account has unpaid events or a negative balance ("cuenta sin saldo operativo").
unpaid_events *integerLive events registered without credits and not yet settled (one credit each).

WebhookEnvelope

Common webhook body, sent as POST with Content-Type: application/json. Headers: X-SC-Webhook-Id (the envelope id, stable across retries: use it to de-duplicate), X-SC-Timestamp (Unix seconds) and X-SC-Signature: v1=<hex>, where <hex> is HMAC-SHA256 with the endpoint secret over <X-SC-Timestamp>.<raw body>. Verify the signature and reject old timestamps (e.g. more than 5 minutes) before processing. Any 2xx acknowledges; otherwise retries with exponential backoff (1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h). An endpoint whose deliveries keep failing is disabled and the account is notified by email. webhook.test is only sent when the account owner asks for a test delivery from the console: a single attempt, no retries, and it never counts towards disabling the endpoint.

The model of data depends on type. New fields may be added to data over time: ignore the ones you do not know.

type data Sent when
certification.completed WebhookCertificationData A certification was issued (verification_code present).
certification.failed WebhookCertificationData A certification could not be issued (incident_id present).
balance.low WebhookBalanceLowData The balance crossed an alert threshold downwards.
balance.exhausted WebhookBalanceExhaustedData The first event was registered as unpaid.
events.unpaid_limit_reached WebhookUnpaidLimitData The unpaid-events limit was reached: registrations are rejected.
consumption.limit_reached WebhookConsumptionLimitData A consumption limit reached its maximum for the period.
recharge.auto_completed WebhookAutoRechargeData An automatic top-up was charged and its credits added.
recharge.auto_failed WebhookAutoRechargeData An automatic top-up failed; automatic top-up was turned off.
webhook.test WebhookTestData The account owner asked for a test delivery.

Example (balance.low):

{"id": "ntc_…", "type": "balance.low", "created_at": "2026-09-28T07:00:16.526317Z", "mode": "live",
 "data": {"threshold_id": "thr_…", "threshold": 1000, "balance": 999}}
FieldType
id *stringNotice id (ntc_…; tst_… for test deliveries), the same on every retry. Also in X-SC-Webhook-Id.
type *string: certification.completed · certification.failed · balance.low · balance.exhausted · events.unpaid_limit_reached · consumption.limit_reached · recharge.auto_completed · recharge.auto_failed · webhook.test
created_at *string (date-time)When the notice was generated. UTC, microseconds (see Formats).
mode *string: live · testMode of the fact notified. Account and balance notices are always live; certification notices carry the mode of the certification.
data *WebhookCertificationData | WebhookBalanceLowData | WebhookBalanceExhaustedData | WebhookUnpaidLimitData | WebhookConsumptionLimitData | WebhookAutoRechargeData | WebhookTestDataPayload of the notice. Its model depends on type (see the table above).

WebhookCertificationData

data of certification.completed and certification.failed.

FieldType
certification_id *stringCertification id (CERT-2026-0000001, CERT-TEST-2026-0000001 in test). Use it with GET /certifications/{certification_id}.
channel_id *string
status *string: completed · failed
event_count *integerEvents in the certified range.
verification_codestringPublic verification code (SC-2026-XXXX-XXXX, SC-TEST-… in test). Only in certification.completed.
incident_idstringIncident reference for support. Only in certification.failed.

WebhookBalanceLowData

data of balance.low.

FieldType
threshold_id *stringId of the alert threshold that was crossed (thr_…).
threshold *integerThe threshold, in credits.
balance *integerBalance in credits right after the crossing.

WebhookBalanceExhaustedData

data of balance.exhausted.

FieldType
channel_id *stringChannel of the first event registered as unpaid.

WebhookUnpaidLimitData

data of events.unpaid_limit_reached.

FieldType
unpaid_limit *integerThe account's unpaid-events limit.
unpaid_events *integerUnpaid events at this moment (equal to the limit).
unpaid_credits *integerCredits owed for them (one per event).

WebhookConsumptionLimitData

data of consumption.limit_reached.

FieldType
limit_id *stringId of the consumption limit (lim_…).
scope *string: channel · keyWhether the limit applies to a whole channel or to one API key.
channel_id *stringChannel of the event that reached the limit.
key_id *string | nullAPI key id (key_…) when scope is key; null for channel limits.
period *string: day · month
period_key *stringThe period that reached the limit, UTC calendar day YYYY-MM-DD or month YYYY-MM.
max_events *integerEvents allowed per period.
action *string: warn · blockwarn: registrations keep going through. block: 422 limit_blocked until the next period.

WebhookAutoRechargeData

data of recharge.auto_completed and recharge.auto_failed.

FieldType
recharge_id *string | nullThe purchase (its Safe Creative sale code). null when it failed before any purchase was created.
pack_id *stringThe pack configured for automatic top-up.
credits *integer | nullCredits of the pack bought. null when it failed before any purchase was created.
amount *string | nullNet price of the pack, before taxes, as a decimal string. null when it failed before any purchase was created.
currency *string | null: EUR · GBP · USD · nullCurrency of amount, that of the owner's pricing region.
threshold *integerThe automatic top-up threshold, in credits.
balanceintegerrecharge.auto_completed only: balance in credits after adding the pack.
reasonstring: payment_failed · sale_creation_failed · payment_method_missing · pack_unavailable · pricing_country_required · daily_limit · account_suspended · custom_pack_inactiverecharge.auto_failed only: payment_failed (the charge was declined), sale_creation_failed (Safe Creative could not create the purchase, e.g. an expired payment method), payment_method_missing (no valid default payment method), pack_unavailable (the pack is no longer on sale), pricing_country_required (no billing country), daily_limit (daily maximum of automatic top-ups reached), account_suspended or custom_pack_inactive (the custom pack it bought was deactivated; it is turned off at that moment, without any purchase attempt).
payment_urlstring | nullrecharge.auto_failed only: page to pay the purchase manually when it was created but not charged.
auto_recharge_disabledbooleanrecharge.auto_failed only: always true; automatic top-up was turned off and keeps its settings.

WebhookTestData

data of webhook.test.

FieldType
endpoint_id *stringThe endpoint (whk_…) the test was requested for.
message *string

Error

FieldType
code *string: validation_error · invalid_key · revoked_key · account_not_operational · unpaid_limit_exceeded · insufficient_balance · not_found · client_ref_conflict · payload_too_large · limit_blocked · rate_limited · test_quota_exceeded · internal · temporarily_unavailable · suspended · account_disabled
message *stringHuman-readable; EN by default, ES via Accept-Language.
doc_urlstring | null
incident_idstring | nullPresent on 5xx responses.