Platform
Auth, sessions, devices, tenants, roles, sync feeds and the health probes.
59 endpoints
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
requests | object[] | required | min items 1 · max items 25 |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Query parameters
| Name | Type | Constraints | |
|---|---|---|---|
updated_since | string | null | optional | — |
cursor | string | null | optional | max length 200 |
per_page | integer | null | optional | min 1 · max 500 |
refresh | string | null | optional | true false 1 0 |
zone | string | null | optional | — |
Response
Returns { "data": [GraphStudent] } with meta.next_cursor for the next page.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
deleted | boolean | required | — |
updated_at | string (date-time) | required | — |
first_name | string | optional | — |
middle_name | string | null | optional | — |
last_name | string | null | optional | — |
gender | string | null | optional | — |
dob | string | null | optional | — |
grade | string | null | optional | — |
status | string | optional | — |
rider_status | RiderStatus | optional | — |
presence | any | optional | — |
external_ref | string | null | optional | — |
photo | any | optional | — |
tags | object[] | optional | — |
guardians | GraphGuardian[] | optional | — |
wallets | GraphWallet[] | optional | — |
bands | GraphBand[] | optional | — |
trip_plans | GraphTripPlan[] | optional | — |
dropoff | any | optional | — |
home | any | optional | — |
home_locations | HomeLocation[] | optional | — |
the driver's trip history. Reuses the `trip` delta feed (updated_since + cursor + ETag) under a history-scoped path; the generic sync/{feed} route no longer serves `trip`.
Query parameters
| Name | Type | Constraints | |
|---|---|---|---|
updated_since | string | null | optional | — |
cursor | string | null | optional | max length 200 |
per_page | integer | null | optional | min 1 · max 500 |
refresh | string | null | optional | true false 1 0 |
zone | string | null | optional | — |
Response
Returns { "data": [Trip] } with meta.next_cursor for the next page.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
trip_plan_id | string | null | optional | — |
route_id | string | null | optional | — |
zone_id | string | null | optional | — |
bus_zone_id | string | null | optional | — |
driver_user_id | string | null | optional | — |
status | string | optional | — |
direction | string | optional | — |
label | string | null | optional | — |
route_name | string | null | optional | — |
started_at | string | null | optional | — |
ended_at | string | null | optional | — |
expected_riders | integer | null | optional | — |
boarded_riders | integer | null | optional | — |
absent_count | integer | null | optional | — |
issues_count | integer | null | optional | — |
bus_capacity | integer | null | optional | — |
updated_at | string (date-time) | required | — |
deleted | boolean | required | — |
the token's identity, no guessing from bodies.
Response
Returns { "data": Profile }.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
first_name | string | required | — |
middle_name | string | null | required | — |
last_name | string | null | required | — |
phone | string | required | — |
email | string | null | required | — |
staff_kind | string | null | required | — |
status | string | required | — |
tenant_id | string | null | required | — |
audience | ApiAudience | required | — |
the §12.5 credential-set step (argon2id via the hashing config). Serves both first-set (migrated NULL hash) and change.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
password | string | required | min length 10 · max length 255 |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
v2 is-pin-required (§2.5): the caller's account-wallet PIN state.
Response
Returns { "data": PinStatus }.
| Field | Type | Constraints | |
|---|---|---|---|
set | boolean | required | — |
required | boolean | required | — |
set/replace, OTP-gated (v2 reset-pin, §2.5).
Request body
| Field | Type | Constraints | |
|---|---|---|---|
challenge_id | string (uuid) | required | — |
otp | string | required | — |
pin | string | required | — |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
mint the OTP gate the PIN set/replace requires (§2.5).
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
v2 validate-wallet-pin (§2.5), throttled at the route.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
pin | string | required | — |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Path parameters
| Name | Type | Notes |
|---|---|---|
feed | string |
Query parameters
| Name | Type | Constraints | |
|---|---|---|---|
updated_since | string | null | optional | — |
cursor | string | null | optional | max length 200 |
per_page | integer | null | optional | min 1 · max 500 |
refresh | string | null | optional | true false 1 0 |
zone | string | null | optional | — |
Response
An array of any.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
client_id | string (uuid) | required | — |
client_secret | string | required | min length 16 · max length 200 |
Response
Returns { "data": ClientToken }.
| Field | Type | Constraints | |
|---|---|---|---|
access_token | string | required | — |
token_type | string | required | — |
expires_in | integer | required | — |
scopes | string[] | required | — |
phone (+password for staff) → OTP challenge.
Staff OTP-skip (§2.1): when auth.driver_otp_skip is on and a driver_app OR beneficiary_app user signs in with a valid password, the password IS the second factor, so we mint the session directly (one round trip) instead of an OTP challenge. Both mobile staff apps (terrago + waas) log in the same way — phone + password — and send the device{fingerprint, serial} block on the login call so DeviceGuard binds the session to BOTH the fingerprint and the serial.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
phone | string | null | optional | max length 20 |
email | string | null | optional | max length 254 |
password | string | null | optional | max length 255 |
audience | string | required | driver_app beneficiary_app parent_app admin_web pass_app pass_web |
device | DeviceInput | optional | — |
Response
Returns { "data": AuthSession }.
| Field | Type | Constraints | |
|---|---|---|---|
otp_required | boolean | required | — |
access_token | string | optional | — |
token_type | string | optional | — |
expires_in | integer | optional | — |
refresh_token | string | optional | — |
must_set_password | boolean | optional | — |
bootstrap | any | optional | — |
challenge_id | string | optional | — |
otp_delivery | string | optional | — |
otp_masked_to | string | optional | — |
debug_otp | string | optional | — |
revoke this device session.
Response
Returns { "data": Ack }.
| Field | Type | Constraints | |
|---|---|---|---|
ok | boolean | required | — |
send a code to a staff account's own contact.
Answers identically whether or not the identifier matches, same as the fan claim and the v2 pair before it: an endpoint that says "no such user" is an account-existence oracle, and this one is unauthenticated by necessity.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
phone | string | null | optional | — |
email | string | null | optional | max length 160 |
Response
Returns { "data": PassFanClaim }.
| Field | Type | Constraints | |
|---|---|---|---|
sent | boolean | required | — |
challenge_id | string | null | required | — |
expires_in | integer | null | required | — |
code + a new password, in one call.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
challenge_id | string (uuid) | required | — |
otp | string | required | min length 6 · max length 6 |
password | string | required | min length 10 · max length 255 |
Response
Returns { "data": PasswordDone }.
| Field | Type | Constraints | |
|---|---|---|---|
reset | boolean | required | — |
rotate; reuse of a rotated token kills the session.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
refresh_token | string | required | max length 100 |
push_token | string | null | optional | max length 4096 |
Response
Returns { "data": AuthTokens }.
| Field | Type | Constraints | |
|---|---|---|---|
access_token | string | required | — |
token_type | string | required | — |
expires_in | integer | required | — |
refresh_token | string | required | — |
OTP → tokens + the bootstrap payload, one round trip.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
challenge_id | string (uuid) | required | — |
otp | string | required | — |
device | DeviceInput | optional | — |
Response
Returns { "data": AuthSession }.
| Field | Type | Constraints | |
|---|---|---|---|
otp_required | boolean | required | — |
access_token | string | optional | — |
token_type | string | optional | — |
expires_in | integer | optional | — |
refresh_token | string | optional | — |
must_set_password | boolean | optional | — |
bootstrap | any | optional | — |
challenge_id | string | optional | — |
otp_delivery | string | optional | — |
otp_masked_to | string | optional | — |
debug_otp | string | optional | — |
Response
Returns { "data": BootstrapEnvelope }.
| Field | Type | Constraints | |
|---|---|---|---|
server_time | string (date-time) | required | — |
audience | string | required | — |
product | string | required | — |
app | BootstrapApp | optional | — |
console | BootstrapConsole | optional | — |
pass | BootstrapPass | optional | — |
"this person exists", from whoever signed them up.
Upsert on the phone number, which is the identity a USSD caller actually has: they are calling FROM it, so the network has already proved it in a way no OTP improves on.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
first_name | string | required | max length 100 |
middle_name | string | null | optional | max length 100 |
last_name | string | null | optional | max length 100 |
phone | string | required | max length 20 |
email | string | null | optional | max length 254 |
gender | string | null | optional | male female unspecified |
national_id | string | null | optional | max length 32 |
external_ref | string | null | optional | max length 64 |
Response
Returns { "data": MachinePersonSync }.
| Field | Type | Constraints | |
|---|---|---|---|
account_id | string (uuid) | required | — |
created | boolean | required | — |
wallet_opened | boolean | required | — |
"money arrived, somewhere terra cannot see".
The M-Pesa paybill (874900) belongs to Cloud9Pay and its Daraja callbacks are registered against WaaS v2, so Safaricom posts to api.terrasofthq.com and never to terra. Repointing that is not ours to do — the shortcode is not ours. So v2 credits its own wallet as it always has and forwards the confirmed payment here, and a fan who tops up at the till sees it in Pass instead of only in a system they never use.
IDEMPOTENT ON THE PROVIDER REFERENCE, which is the whole safety of it: M-Pesa re-delivers callbacks, v2 dedupes on the same TransID, and the ledger key below carries it so a replay lands on the transaction that already exists rather than inventing money.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
phone | string | required | max length 20 |
amount_minor | integer | required | min 1 |
currency_code | string | required | min length 3 · max length 3 |
reference | string | required | max length 64 |
gateway | string | null | optional | max length 32 |
Response
Returns { "data": MachineWalletCredit }.
| Field | Type | Constraints | |
|---|---|---|---|
transaction_id | string (uuid) | required | — |
wallet_id | string (uuid) | required | — |
"money left, on somebody else's rail" (C9-2).
The mirror of walletCredit(), and the direction that can hurt somebody. Cloud9 makes the M-Pesa B2C payout terra cannot yet make, so a fan withdrawing at an event is paid by them and terra is told; terra's ledger stays the authoritative balance either way, which is the whole point — two systems with an opinion about what a person has is how a guest gets refused at a bar holding money they can see in an app.
IDEMPOTENT ON THE PROVIDER REFERENCE, exactly as the credit is. The asymmetry is what a replay COSTS: a duplicated credit invents money and an accountant finds it, a duplicated debit takes a real person's balance twice and they find it, at the bar, at 1am.
Insufficient funds is a REFUSAL, not an error — the ledger records the failed transaction (§5.5) before throwing, so a partner arguing about a rejected payout has a row to point at.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
phone | string | required | max length 20 |
amount_minor | integer | required | min 1 |
currency_code | string | required | min length 3 · max length 3 |
reference | string | required | max length 64 |
gateway | string | required | max length 32 |
Response
Returns { "data": MachineWalletDebit }.
| Field | Type | Constraints | |
|---|---|---|---|
transaction_id | string (uuid) | required | — |
wallet_id | string (uuid) | required | — |
"they removed it".
Optional means removable. Without this, a PIN set by mistake on a feature phone could only ever be changed, never cleared, and the wallet would be locked to whoever knew it.
Query parameters
| Name | Type | Constraints | |
|---|---|---|---|
phone | string | required | max length 20 |
pin | string | null | optional | — |
Response
Returns { "data": MachinePinSet }.
| Field | Type | Constraints | |
|---|---|---|---|
wallets_updated | integer | required | — |
"this person chose this PIN".
The one that is broken today: a PIN set on the v2 USSD is written to v2's own column and dropped by the ETL, so the guest is still charged as though they had set nothing. Written here it takes effect on the very next tap — both charge paths read the wallet row live, with no cache in front of it.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
phone | string | required | max length 20 |
pin | string | null | optional | — |
Response
Returns { "data": MachinePinSet }.
| Field | Type | Constraints | |
|---|---|---|---|
wallets_updated | integer | required | — |
revoke this device session.
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Response
Returns { "data": [ApiClient] } with meta.next_cursor for the next page.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
tenant_id | string | null | required | — |
audience | string | required | — |
name | string | required | — |
scopes | string[] | required | — |
rate_tier | string | required | — |
status | string | required | — |
created_at | string | required | — |
Request body
| Field | Type | Constraints | |
|---|---|---|---|
name | string | required | max length 120 |
audience | string | null | optional | partner ussd |
tenant_id | string | null | optional | — |
scopes | string[] | optional | max items 40 |
rate_tier | string | null | optional | standard elevated |
Response
Returns { "data": ApiClientCreated }.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
tenant_id | string | null | required | — |
audience | string | required | — |
name | string | required | — |
scopes | string[] | required | — |
rate_tier | string | required | — |
status | string | required | — |
created_at | string | required | — |
client_secret | string | required | — |
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": Ack }.
| Field | Type | Constraints | |
|---|---|---|---|
ok | boolean | required | — |
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": ApiClientCreated }.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
tenant_id | string | null | required | — |
audience | string | required | — |
name | string | required | — |
scopes | string[] | required | — |
rate_tier | string | required | — |
status | string | required | — |
created_at | string | required | — |
client_secret | string | required | — |
Query parameters
| Name | Type | Constraints | |
|---|---|---|---|
school_id | string | null | optional | — |
actor_id | string | null | optional | — |
action | string | null | optional | max length 60 |
shadow_only | boolean | optional | — |
cursor | string | null | optional | max length 200 |
per_page | integer | optional | min 1 · max 100 |
Response
Returns { "data": [AuditEntry] } with meta.next_cursor for the next page.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
action | string | required | — |
entity_type | string | required | — |
entity_id | string | null | required | — |
changes | any | required | — |
school_id | string | null | required | — |
school_name | string | null | required | — |
actor_name | string | required | — |
shadow_operator_name | string | null | required | — |
ip | string | null | required | — |
created_at | string | required | — |
Request body
| Field | Type | Constraints | |
|---|---|---|---|
tenant_id | string (uuid) | required | — |
Response
Returns { "data": TenantSwitched }.
| Field | Type | Constraints | |
|---|---|---|---|
access_token | string | required | — |
token_type | string | required | — |
expires_in | integer | required | — |
tenant_id | string (uuid) | required | — |
Request body
| Field | Type | Constraints | |
|---|---|---|---|
school_id | string (uuid) | required | — |
Response
Returns { "data": ShadowSession }.
| Field | Type | Constraints | |
|---|---|---|---|
access_token | string | required | — |
token_type | string | required | — |
expires_in | integer | required | — |
school_id | string (uuid) | required | — |
school_name | string | required | — |
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": Deleted }.
| Field | Type | Constraints | |
|---|---|---|---|
deleted | boolean | required | — |
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": Photo }.
| Field | Type | Constraints | |
|---|---|---|---|
url | string | required | — |
medium | string | required | — |
thumb | string | required | — |
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": Deleted }.
| Field | Type | Constraints | |
|---|---|---|---|
deleted | boolean | required | — |
The POS catalog's images (PCE-5/6): same pipeline, two more owners.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": Photo }.
| Field | Type | Constraints | |
|---|---|---|---|
url | string | required | — |
medium | string | required | — |
thumb | string | required | — |
Response
Returns { "data": PreferenceDocument }.
No declared fields.
Request body
| Field | Type | Constraints | |
|---|---|---|---|
preferences | array | required | max items 40 |
Response
Returns { "data": PreferenceDocument }.
No declared fields.
the SAME document, for a school the caller is not inside. Platform operators only; the route group enforces that, so this only has to prove the school exists.
Path parameters
| Name | Type | Notes |
|---|---|---|
school | string |
Response
Returns { "data": TenantSettingsDoc }.
| Field | Type | Constraints | |
|---|---|---|---|
flags | object | optional | — |
notify_requires_subscription | boolean | null | required | — |
notify_delay_seconds | integer | null | required | — |
metered_messaging | boolean | required | — |
attendance | any | required | — |
vocabulary | object | required | — |
menu_hidden | string[] | required | — |
school_profile | any | required | — |
help_center | any | required | — |
company_info | any | optional | — |
impact_baselines | ImpactBaseline[] | required | — |
the operator configuring a school from outside it (its Help Center credential, notification policy, onboarding profile). Identical semantics to {@see update}; only the tenant the sections land on differs, which is why both share applySections().
Path parameters
| Name | Type | Notes |
|---|---|---|
school | string |
Request body
| Field | Type | Constraints | |
|---|---|---|---|
settings | array | required | — |
settings.flags | array | optional | max items 20 |
settings.notify_requires_subscription | boolean | null | optional | — |
settings.notify_delay_seconds | integer | null | optional | min 0 · max 86400 |
settings.metered_messaging | boolean | optional | — |
settings.attendance | array | null | optional | — |
settings.vocabulary | string[] | optional | max items 100 |
settings.menu_hidden | string[] | optional | max items 100 |
settings.school_profile | array | null | optional | — |
settings.help_center | array | null | optional | — |
settings.company_info | array | null | optional | — |
settings.impact_baselines | object[] | optional | max items 4 |
Response
Returns { "data": TenantSettingsDoc }.
| Field | Type | Constraints | |
|---|---|---|---|
flags | object | optional | — |
notify_requires_subscription | boolean | null | required | — |
notify_delay_seconds | integer | null | required | — |
metered_messaging | boolean | required | — |
attendance | any | required | — |
vocabulary | object | required | — |
menu_hidden | string[] | required | — |
school_profile | any | required | — |
help_center | any | required | — |
company_info | any | optional | — |
impact_baselines | ImpactBaseline[] | required | — |
Response
Returns { "data": TenantSettingsDoc }.
| Field | Type | Constraints | |
|---|---|---|---|
flags | object | optional | — |
notify_requires_subscription | boolean | null | required | — |
notify_delay_seconds | integer | null | required | — |
metered_messaging | boolean | required | — |
attendance | any | required | — |
vocabulary | object | required | — |
menu_hidden | string[] | required | — |
school_profile | any | required | — |
help_center | any | required | — |
company_info | any | optional | — |
impact_baselines | ImpactBaseline[] | required | — |
Request body
| Field | Type | Constraints | |
|---|---|---|---|
settings | array | required | — |
settings.flags | array | optional | max items 20 |
settings.notify_requires_subscription | boolean | null | optional | — |
settings.notify_delay_seconds | integer | null | optional | min 0 · max 86400 |
settings.metered_messaging | boolean | optional | — |
settings.attendance | array | null | optional | — |
settings.vocabulary | string[] | optional | max items 100 |
settings.menu_hidden | string[] | optional | max items 100 |
settings.school_profile | array | null | optional | — |
settings.help_center | array | null | optional | — |
settings.company_info | array | null | optional | — |
settings.impact_baselines | object[] | optional | max items 4 |
Response
Returns { "data": TenantSettingsDoc }.
| Field | Type | Constraints | |
|---|---|---|---|
flags | object | optional | — |
notify_requires_subscription | boolean | null | required | — |
notify_delay_seconds | integer | null | required | — |
metered_messaging | boolean | required | — |
attendance | any | required | — |
vocabulary | object | required | — |
menu_hidden | string[] | required | — |
school_profile | any | required | — |
help_center | any | required | — |
company_info | any | optional | — |
impact_baselines | ImpactBaseline[] | required | — |
Response
Returns { "data": [WebhookEndpoint] } with meta.next_cursor for the next page.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
name | string | required | — |
url | string | required | — |
event_types | string[] | required | — |
status | string | required | — |
last_at | string | null | required | — |
last_ok | boolean | null | required | — |
ok_24h | integer | required | — |
failed_24h | integer | required | — |
tenant_name | string | null | required | — |
Request body
| Field | Type | Constraints | |
|---|---|---|---|
name | string | required | min length 2 · max length 80 |
url | string (uri) | required | max length 300 |
event_types | string[] | optional | max items 20 |
Response
Returns { "data": WebhookSecret }.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
secret | string | required | — |
The delivery log (§11.14). One row per ATTEMPT, so a partner asking "did you send it?" gets the retry ladder rather than a final verdict. `failed=1` is the triage view — the reason anyone opens this screen.
Response
Returns { "data": [WebhookDelivery] } with meta.next_cursor for the next page.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
endpoint_id | string (uuid) | required | — |
endpoint_name | string | required | — |
endpoint_url | string | required | — |
event_id | string | required | — |
event_type | string | required | — |
attempt | integer | required | — |
ok | boolean | required | — |
status_code | integer | null | required | — |
error | string | null | required | — |
response_body | string | null | required | — |
duration_ms | integer | required | — |
created_at | string (date-time) | required | — |
tenant_name | string | null | required | — |
can_retry | boolean | required | — |
Send one delivery again (§11.14).
The log could always say a callback failed and never do anything about it, so a partner outage cost the events in its window permanently. This re-sends the ORIGINAL signed envelope — same event_id, so a partner that did receive the first copy can recognise the duplicate and drop it.
Answers with the outcome rather than a bare 204, because the three ways this legitimately does nothing are different conversations: the endpoint is switched off, or the body predates 0159 and was never kept.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": WebhookRetry }.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
status | string | required | — |
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Request body
| Field | Type | Constraints | |
|---|---|---|---|
name | string | optional | min length 2 · max length 80 |
url | string (uri) | optional | max length 300 |
event_types | string[] | optional | max items 20 |
status | string | optional | active suspended |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Rotate the signing secret (§11.14): a fresh key returned ONCE — the old one stops signing immediately. Delete+recreate is no longer the only recovery for a leaked or lost secret.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": WebhookSecret }.
| Field | Type | Constraints | |
|---|---|---|---|
id | string (uuid) | required | — |
secret | string | required | — |
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.
The POS catalog's images (PCE-5/6): same pipeline, two more owners.
Path parameters
| Name | Type | Notes |
|---|---|---|
id | string |
Response
Returns { "data": … }; this endpoint's payload is not yet
pinned to a named shape.