Skip to content

Set Integration Credentials

POST
/api/webhooks/integrations/{integration_uuid}/credentials
curl --request POST \
--url https://app.lionrapid.com/api/webhooks/integrations/example/credentials \
--header 'Content-Type: application/json' \
--data '{ "platform": "example", "credentials": {} }'

Receive a platform credential from an OAuth install callback (#65).

svc_-ONLY, WITH NO SECOND PRINCIPAL. The sibling route above admits a project master key for the secrets-stripped view, because reading a config without secrets is a reasonable thing for a customer’s own key to do. WRITING a live credential is not: the caller here is our own Worker finishing an exchange, and it holds the SERVICE_KEY. Widening this to sk_ would mean any project key could replace the access token on its own integration — which sounds harmless until you notice the shop is what decides whose store the write-back reaches.

204, WITH NO BODY, AND THAT IS A SECURITY PROPERTY RATHER THAN A STYLE CHOICE. There is no response shape that could accidentally echo the token back, no serializer to audit, and nothing for a proxy or an error page to capture. The caller already knows what it sent; the only thing it needs from us is whether it landed.

THIS ROUTE CANNOT INVALIDATE THE WORKER’S CACHE, AND THE CALLER MUST. Stated here because the consequence lands on whoever writes the callback, not on whoever reads this file:

  • packages/webhook/src/config.ts caches a resolved config in KV under webhook:{id} for 300s AND in-isolate for 300s, and KV is consulted BEFORE this API. So a config read at any point BEFORE the token is written leaves a token-less copy that outlives the write — and because a second isolate can read the stale KV entry near the end of its window and then memoise it for a further 300s, the worst case is about TEN minutes, not five.
  • The server cannot clear it. The webhook Worker’s CONFIG_KV is a different namespace from the one CF_KV_NAMESPACE_ID points at, and CloudflareKvService hardcodes config:{domain} keys for the edge proxy. There is no server→Worker invalidation path and this endpoint does not invent one.

So the Worker half owns it, and cheaply: the surest fix is for /auth NOT to resolve the config at all — it needs the integration uuid and the shop, neither of which requires a config fetch — because then nothing token-less is ever cached and there is nothing to invalidate. Belt and braces, the callback should also CONFIG_KV.delete('webhook:{id}') and call the already-exported clearConfigCache(id) after this route returns 204.

integration_uuid
required
Integration Uuid
string
x-api-key
Any of:
string
Media typeapplication/json
SetIntegrationCredentialsRequest

The OAuth callback handing back a platform credential (#65).

Config has always flowed ONE WAY — server → KV → Worker — and POST /integrations writes credentials once, at creation, from a form someone filled in. An OAuth install inverts that for exactly one field: the Worker finishes the exchange, holds an access token, and has nowhere to put it. This is that place, and deliberately nothing more — it cannot create an integration, change its namespace, its locales or its mode.

platform is REQUIRED and is checked against the integration’s own platform rather than trusted. It is not redundant with the uuid: it makes a caller state which credential shape it believes it is sending, so writing a Shopify token onto a Contentful integration is a 409 instead of a silently corrupt config that fails at the next write-back.

object
platform
required
Platform
string
credentials
Credentials
object
Examplegenerated
{
"platform": "example",
"credentials": {}
}

Successful Response

Validation Error

Media typeapplication/json
HTTPValidationError
object
detail
Detail
Array<object>
ValidationError
object
loc
required
Location
Array
msg
required
Message
string
type
required
Error Type
string
Examplegenerated
{
"detail": [
{
"loc": [
"example"
],
"msg": "example",
"type": "example"
}
]
}