Platform

Auth, sessions, devices, tenants, roles, sync feeds and the health probes.

59 endpoints

GET /healthz #
public

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

GET /heartbeatz #
public

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

GET /readyz #
public

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/app/account/{id}/photo #
bearer driver_app beneficiary_app people.update device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/app/batch #
bearer driver_app beneficiary_app parent_app device credential

Request body

FieldTypeConstraints
requestsobject[]requiredmin items 1 · max items 25

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

GET /v3/app/graph #
bearer driver_app beneficiary_app parent_app device credential

Query parameters

NameTypeConstraints
updated_sincestring | nulloptional
cursorstring | nulloptionalmax length 200
per_pageinteger | nulloptionalmin 1 · max 500
refreshstring | nulloptionaltrue false 1 0
zonestring | nulloptional

Response

Returns { "data": [GraphStudent] } with meta.next_cursor for the next page.

FieldTypeConstraints
idstring (uuid)required
deletedbooleanrequired
updated_atstring (date-time)required
first_namestringoptional
middle_namestring | nulloptional
last_namestring | nulloptional
genderstring | nulloptional
dobstring | nulloptional
gradestring | nulloptional
statusstringoptional
rider_statusRiderStatusoptional
presenceanyoptional
external_refstring | nulloptional
photoanyoptional
tagsobject[]optional
guardiansGraphGuardian[]optional
walletsGraphWallet[]optional
bandsGraphBand[]optional
trip_plansGraphTripPlan[]optional
dropoffanyoptional
homeanyoptional
home_locationsHomeLocation[]optional
GET /v3/app/history/trips #
bearer driver_app beneficiary_app parent_app device credential

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

NameTypeConstraints
updated_sincestring | nulloptional
cursorstring | nulloptionalmax length 200
per_pageinteger | nulloptionalmin 1 · max 500
refreshstring | nulloptionaltrue false 1 0
zonestring | nulloptional

Response

Returns { "data": [Trip] } with meta.next_cursor for the next page.

FieldTypeConstraints
idstring (uuid)required
trip_plan_idstring | nulloptional
route_idstring | nulloptional
zone_idstring | nulloptional
bus_zone_idstring | nulloptional
driver_user_idstring | nulloptional
statusstringoptional
directionstringoptional
labelstring | nulloptional
route_namestring | nulloptional
started_atstring | nulloptional
ended_atstring | nulloptional
expected_ridersinteger | nulloptional
boarded_ridersinteger | nulloptional
absent_countinteger | nulloptional
issues_countinteger | nulloptional
bus_capacityinteger | nulloptional
updated_atstring (date-time)required
deletedbooleanrequired
GET /v3/app/profile #
bearer driver_app beneficiary_app parent_app device credential

the token's identity, no guessing from bodies.

Response

Returns { "data": Profile }.

FieldTypeConstraints
idstring (uuid)required
first_namestringrequired
middle_namestring | nullrequired
last_namestring | nullrequired
phonestringrequired
emailstring | nullrequired
staff_kindstring | nullrequired
statusstringrequired
tenant_idstring | nullrequired
audienceApiAudiencerequired
PUT /v3/app/profile/password #
bearer driver_app beneficiary_app parent_app device credential

the §12.5 credential-set step (argon2id via the hashing config). Serves both first-set (migrated NULL hash) and change.

Request body

FieldTypeConstraints
passwordstringrequiredmin length 10 · max length 255

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/app/profile/photo #
bearer driver_app beneficiary_app parent_app device credential

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

GET /v3/app/profile/pin #
bearer driver_app beneficiary_app parent_app device credential

v2 is-pin-required (§2.5): the caller's account-wallet PIN state.

Response

Returns { "data": PinStatus }.

FieldTypeConstraints
setbooleanrequired
requiredbooleanrequired
PUT /v3/app/profile/pin #
bearer driver_app beneficiary_app parent_app device credential

set/replace, OTP-gated (v2 reset-pin, §2.5).

Request body

FieldTypeConstraints
challenge_idstring (uuid)required
otpstringrequired
pinstringrequired

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/app/profile/pin/challenge #
bearer driver_app beneficiary_app parent_app device credential

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.

POST /v3/app/profile/pin/validate #
bearer driver_app beneficiary_app parent_app device credential

v2 validate-wallet-pin (§2.5), throttled at the route.

Request body

FieldTypeConstraints
pinstringrequired

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

DELETE /v3/app/student/{id}/photo #
bearer driver_app beneficiary_app people.update device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/app/student/{id}/photo #
bearer driver_app beneficiary_app people.update device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

GET /v3/app/sync/{feed} #
bearer driver_app beneficiary_app parent_app device credential

Path parameters

NameTypeNotes
feedstring

Query parameters

NameTypeConstraints
updated_sincestring | nulloptional
cursorstring | nulloptionalmax length 200
per_pageinteger | nulloptionalmin 1 · max 500
refreshstring | nulloptionaltrue false 1 0
zonestring | nulloptional

Response

An array of any.

POST /v3/auth/client #
public login

Request body

FieldTypeConstraints
client_idstring (uuid)required
client_secretstringrequiredmin length 16 · max length 200

Response

Returns { "data": ClientToken }.

FieldTypeConstraints
access_tokenstringrequired
token_typestringrequired
expires_inintegerrequired
scopesstring[]required
POST /v3/auth/login #
public login

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

FieldTypeConstraints
phonestring | nulloptionalmax length 20
emailstring | nulloptionalmax length 254
passwordstring | nulloptionalmax length 255
audiencestringrequireddriver_app beneficiary_app parent_app admin_web pass_app pass_web
deviceDeviceInputoptional

Response

Returns { "data": AuthSession }.

FieldTypeConstraints
otp_requiredbooleanrequired
access_tokenstringoptional
token_typestringoptional
expires_inintegeroptional
refresh_tokenstringoptional
must_set_passwordbooleanoptional
bootstrapanyoptional
challenge_idstringoptional
otp_deliverystringoptional
otp_masked_tostringoptional
debug_otpstringoptional
POST /v3/auth/logout #
bearer driver_app beneficiary_app parent_app pass_app pass_web admin_web device credential

revoke this device session.

Response

Returns { "data": Ack }.

FieldTypeConstraints
okbooleanrequired
POST /v3/auth/password/forgot #
public login

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

FieldTypeConstraints
phonestring | nulloptional
emailstring | nulloptionalmax length 160

Response

Returns { "data": PassFanClaim }.

FieldTypeConstraints
sentbooleanrequired
challenge_idstring | nullrequired
expires_ininteger | nullrequired
POST /v3/auth/password/reset #
public 10,1

code + a new password, in one call.

Request body

FieldTypeConstraints
challenge_idstring (uuid)required
otpstringrequiredmin length 6 · max length 6
passwordstringrequiredmin length 10 · max length 255

Response

Returns { "data": PasswordDone }.

FieldTypeConstraints
resetbooleanrequired
POST /v3/auth/refresh #
public 30,1

rotate; reuse of a rotated token kills the session.

Request body

FieldTypeConstraints
refresh_tokenstringrequiredmax length 100
push_tokenstring | nulloptionalmax length 4096

Response

Returns { "data": AuthTokens }.

FieldTypeConstraints
access_tokenstringrequired
token_typestringrequired
expires_inintegerrequired
refresh_tokenstringrequired
POST /v3/auth/session #
public 10,1

OTP → tokens + the bootstrap payload, one round trip.

Request body

FieldTypeConstraints
challenge_idstring (uuid)required
otpstringrequired
deviceDeviceInputoptional

Response

Returns { "data": AuthSession }.

FieldTypeConstraints
otp_requiredbooleanrequired
access_tokenstringoptional
token_typestringoptional
expires_inintegeroptional
refresh_tokenstringoptional
must_set_passwordbooleanoptional
bootstrapanyoptional
challenge_idstringoptional
otp_deliverystringoptional
otp_masked_tostringoptional
debug_otpstringoptional
GET /v3/bootstrap #
bearer driver_app beneficiary_app parent_app admin_web pass_app pass_web device credential

Response

Returns { "data": BootstrapEnvelope }.

FieldTypeConstraints
server_timestring (date-time)required
audiencestringrequired
productstringrequired
appBootstrapAppoptional
consoleBootstrapConsoleoptional
passBootstrapPassoptional
POST /v3/machine/person #
bearer ussd partner people.create 60,1

"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

FieldTypeConstraints
first_namestringrequiredmax length 100
middle_namestring | nulloptionalmax length 100
last_namestring | nulloptionalmax length 100
phonestringrequiredmax length 20
emailstring | nulloptionalmax length 254
genderstring | nulloptionalmale female unspecified
national_idstring | nulloptionalmax length 32
external_refstring | nulloptionalmax length 64

Response

Returns { "data": MachinePersonSync }.

FieldTypeConstraints
account_idstring (uuid)required
createdbooleanrequired
wallet_openedbooleanrequired
POST /v3/machine/wallet-credit #
bearer ussd partner money.adjust 60,1

"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

FieldTypeConstraints
phonestringrequiredmax length 20
amount_minorintegerrequiredmin 1
currency_codestringrequiredmin length 3 · max length 3
referencestringrequiredmax length 64
gatewaystring | nulloptionalmax length 32

Response

Returns { "data": MachineWalletCredit }.

FieldTypeConstraints
transaction_idstring (uuid)required
wallet_idstring (uuid)required
POST /v3/machine/wallet-debit #
bearer ussd partner money.adjust 60,1

"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

FieldTypeConstraints
phonestringrequiredmax length 20
amount_minorintegerrequiredmin 1
currency_codestringrequiredmin length 3 · max length 3
referencestringrequiredmax length 64
gatewaystringrequiredmax length 32

Response

Returns { "data": MachineWalletDebit }.

FieldTypeConstraints
transaction_idstring (uuid)required
wallet_idstring (uuid)required
DELETE /v3/machine/wallet-pin #
bearer ussd partner money.adjust 60,1

"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

NameTypeConstraints
phonestringrequiredmax length 20
pinstring | nulloptional

Response

Returns { "data": MachinePinSet }.

FieldTypeConstraints
wallets_updatedintegerrequired
POST /v3/machine/wallet-pin #
bearer ussd partner money.adjust 60,1

"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

FieldTypeConstraints
phonestringrequiredmax length 20
pinstring | nulloptional

Response

Returns { "data": MachinePinSet }.

FieldTypeConstraints
wallets_updatedintegerrequired
POST /v3/pass/auth/logout #
bearer pass_fan credential

revoke this device session.

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

GET /v3/portal/api-client #
bearer admin_web device credential

Response

Returns { "data": [ApiClient] } with meta.next_cursor for the next page.

FieldTypeConstraints
idstring (uuid)required
tenant_idstring | nullrequired
audiencestringrequired
namestringrequired
scopesstring[]required
rate_tierstringrequired
statusstringrequired
created_atstringrequired
POST /v3/portal/api-client #
bearer admin_web device credential

Request body

FieldTypeConstraints
namestringrequiredmax length 120
audiencestring | nulloptionalpartner ussd
tenant_idstring | nulloptional
scopesstring[]optionalmax items 40
rate_tierstring | nulloptionalstandard elevated

Response

Returns { "data": ApiClientCreated }.

FieldTypeConstraints
idstring (uuid)required
tenant_idstring | nullrequired
audiencestringrequired
namestringrequired
scopesstring[]required
rate_tierstringrequired
statusstringrequired
created_atstringrequired
client_secretstringrequired
DELETE /v3/portal/api-client/{id} #
bearer admin_web device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": Ack }.

FieldTypeConstraints
okbooleanrequired
POST /v3/portal/api-client/{id}/rotate #
bearer admin_web device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": ApiClientCreated }.

FieldTypeConstraints
idstring (uuid)required
tenant_idstring | nullrequired
audiencestringrequired
namestringrequired
scopesstring[]required
rate_tierstringrequired
statusstringrequired
created_atstringrequired
client_secretstringrequired
GET /v3/portal/audit-log #
bearer admin_web device credential

Query parameters

NameTypeConstraints
school_idstring | nulloptional
actor_idstring | nulloptional
actionstring | nulloptionalmax length 60
shadow_onlybooleanoptional
cursorstring | nulloptionalmax length 200
per_pageintegeroptionalmin 1 · max 100

Response

Returns { "data": [AuditEntry] } with meta.next_cursor for the next page.

FieldTypeConstraints
idstring (uuid)required
actionstringrequired
entity_typestringrequired
entity_idstring | nullrequired
changesanyrequired
school_idstring | nullrequired
school_namestring | nullrequired
actor_namestringrequired
shadow_operator_namestring | nullrequired
ipstring | nullrequired
created_atstringrequired
POST /v3/portal/auth/switch-tenant #
bearer admin_web device credential

Request body

FieldTypeConstraints
tenant_idstring (uuid)required

Response

Returns { "data": TenantSwitched }.

FieldTypeConstraints
access_tokenstringrequired
token_typestringrequired
expires_inintegerrequired
tenant_idstring (uuid)required
POST /v3/portal/impersonate #
bearer admin_web device credential

Request body

FieldTypeConstraints
school_idstring (uuid)required

Response

Returns { "data": ShadowSession }.

FieldTypeConstraints
access_tokenstringrequired
token_typestringrequired
expires_inintegerrequired
school_idstring (uuid)required
school_namestringrequired
DELETE /v3/portal/pos-category/{id}/photo #
bearer admin_web settings.manage device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": Deleted }.

FieldTypeConstraints
deletedbooleanrequired
POST /v3/portal/pos-category/{id}/photo #
bearer admin_web settings.manage device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": Photo }.

FieldTypeConstraints
urlstringrequired
mediumstringrequired
thumbstringrequired
DELETE /v3/portal/pos-item/{id}/photo #
bearer admin_web settings.manage device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": Deleted }.

FieldTypeConstraints
deletedbooleanrequired
POST /v3/portal/pos-item/{id}/photo #
bearer admin_web settings.manage device credential

The POS catalog's images (PCE-5/6): same pipeline, two more owners.

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": Photo }.

FieldTypeConstraints
urlstringrequired
mediumstringrequired
thumbstringrequired
GET /v3/portal/preference #
bearer admin_web device credential

Response

Returns { "data": PreferenceDocument }.

No declared fields.

PUT /v3/portal/preference #
bearer admin_web device credential

Request body

FieldTypeConstraints
preferencesarrayrequiredmax items 40

Response

Returns { "data": PreferenceDocument }.

No declared fields.

GET /v3/portal/school/{school}/setting #
bearer admin_web device credential

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

NameTypeNotes
schoolstring

Response

Returns { "data": TenantSettingsDoc }.

FieldTypeConstraints
flagsobjectoptional
notify_requires_subscriptionboolean | nullrequired
notify_delay_secondsinteger | nullrequired
metered_messagingbooleanrequired
attendanceanyrequired
vocabularyobjectrequired
menu_hiddenstring[]required
school_profileanyrequired
help_centeranyrequired
company_infoanyoptional
impact_baselinesImpactBaseline[]required
PUT /v3/portal/school/{school}/setting #
bearer admin_web device credential

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

NameTypeNotes
schoolstring

Request body

FieldTypeConstraints
settingsarrayrequired
settings.flagsarrayoptionalmax items 20
settings.notify_requires_subscriptionboolean | nulloptional
settings.notify_delay_secondsinteger | nulloptionalmin 0 · max 86400
settings.metered_messagingbooleanoptional
settings.attendancearray | nulloptional
settings.vocabularystring[]optionalmax items 100
settings.menu_hiddenstring[]optionalmax items 100
settings.school_profilearray | nulloptional
settings.help_centerarray | nulloptional
settings.company_infoarray | nulloptional
settings.impact_baselinesobject[]optionalmax items 4

Response

Returns { "data": TenantSettingsDoc }.

FieldTypeConstraints
flagsobjectoptional
notify_requires_subscriptionboolean | nullrequired
notify_delay_secondsinteger | nullrequired
metered_messagingbooleanrequired
attendanceanyrequired
vocabularyobjectrequired
menu_hiddenstring[]required
school_profileanyrequired
help_centeranyrequired
company_infoanyoptional
impact_baselinesImpactBaseline[]required
GET /v3/portal/setting #
bearer admin_web device credential

Response

Returns { "data": TenantSettingsDoc }.

FieldTypeConstraints
flagsobjectoptional
notify_requires_subscriptionboolean | nullrequired
notify_delay_secondsinteger | nullrequired
metered_messagingbooleanrequired
attendanceanyrequired
vocabularyobjectrequired
menu_hiddenstring[]required
school_profileanyrequired
help_centeranyrequired
company_infoanyoptional
impact_baselinesImpactBaseline[]required
PUT /v3/portal/setting #
bearer admin_web tenant.manage device credential

Request body

FieldTypeConstraints
settingsarrayrequired
settings.flagsarrayoptionalmax items 20
settings.notify_requires_subscriptionboolean | nulloptional
settings.notify_delay_secondsinteger | nulloptionalmin 0 · max 86400
settings.metered_messagingbooleanoptional
settings.attendancearray | nulloptional
settings.vocabularystring[]optionalmax items 100
settings.menu_hiddenstring[]optionalmax items 100
settings.school_profilearray | nulloptional
settings.help_centerarray | nulloptional
settings.company_infoarray | nulloptional
settings.impact_baselinesobject[]optionalmax items 4

Response

Returns { "data": TenantSettingsDoc }.

FieldTypeConstraints
flagsobjectoptional
notify_requires_subscriptionboolean | nullrequired
notify_delay_secondsinteger | nullrequired
metered_messagingbooleanrequired
attendanceanyrequired
vocabularyobjectrequired
menu_hiddenstring[]required
school_profileanyrequired
help_centeranyrequired
company_infoanyoptional
impact_baselinesImpactBaseline[]required
GET /v3/portal/webhook-endpoint #
bearer admin_web pass_web device credential

Response

Returns { "data": [WebhookEndpoint] } with meta.next_cursor for the next page.

FieldTypeConstraints
idstring (uuid)required
namestringrequired
urlstringrequired
event_typesstring[]required
statusstringrequired
last_atstring | nullrequired
last_okboolean | nullrequired
ok_24hintegerrequired
failed_24hintegerrequired
tenant_namestring | nullrequired
POST /v3/portal/webhook-endpoint #
bearer admin_web tenant.manage device credential

Request body

FieldTypeConstraints
namestringrequiredmin length 2 · max length 80
urlstring (uri)requiredmax length 300
event_typesstring[]optionalmax items 20

Response

Returns { "data": WebhookSecret }.

FieldTypeConstraints
idstring (uuid)required
secretstringrequired
GET /v3/portal/webhook-endpoint/delivery #
bearer admin_web pass_web tenant.manage device credential

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.

FieldTypeConstraints
idstring (uuid)required
endpoint_idstring (uuid)required
endpoint_namestringrequired
endpoint_urlstringrequired
event_idstringrequired
event_typestringrequired
attemptintegerrequired
okbooleanrequired
status_codeinteger | nullrequired
errorstring | nullrequired
response_bodystring | nullrequired
duration_msintegerrequired
created_atstring (date-time)required
tenant_namestring | nullrequired
can_retrybooleanrequired
POST /v3/portal/webhook-endpoint/delivery/{id}/retry #
bearer admin_web pass_web tenant.manage device credential

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

NameTypeNotes
idstring

Response

Returns { "data": WebhookRetry }.

FieldTypeConstraints
idstring (uuid)required
statusstringrequired
DELETE /v3/portal/webhook-endpoint/{id} #
bearer admin_web tenant.manage device credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

PATCH /v3/portal/webhook-endpoint/{id} #
bearer admin_web tenant.manage device credential

Path parameters

NameTypeNotes
idstring

Request body

FieldTypeConstraints
namestringoptionalmin length 2 · max length 80
urlstring (uri)optionalmax length 300
event_typesstring[]optionalmax items 20
statusstringoptionalactive suspended

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/portal/webhook-endpoint/{id}/rotate-secret #
bearer admin_web tenant.manage device credential

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

NameTypeNotes
idstring

Response

Returns { "data": WebhookSecret }.

FieldTypeConstraints
idstring (uuid)required
secretstringrequired
DELETE /v3/waas/pos-category/{id}/photo #
public settings.manage credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/waas/pos-category/{id}/photo #
public settings.manage credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

DELETE /v3/waas/pos-item/{id}/photo #
public settings.manage credential

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.

POST /v3/waas/pos-item/{id}/photo #
public settings.manage credential

The POS catalog's images (PCE-5/6): same pipeline, two more owners.

Path parameters

NameTypeNotes
idstring

Response

Returns { "data": … }; this endpoint's payload is not yet pinned to a named shape.