Inbound API (Desol Int. → this app)
The other direction. On the Jira and Trello pages a user gives a project or a board a label. Here, a Desol Int. service (for example the Workbench) asks this app: “what labels did you give these projects and boards?” It sends their IDs; this app answers with its label for each one.
Desol Int. does not send these calls yet. The endpoint is built and tested against Desol Int.'s published contract, so it works as soon as they do.
Request
GET /desol/v1/labels
?ref=jira%3A7f1c2a90-4d3e-4b21-9a55-0c2e8d11aa01%3Aproject%3A10042
&ref=trello%3Aboard%3A60a1b2c3d4e5f60012345678
&ref=trello%3Aboard%3A60a1b2c3d4e5f60012345999
Host: sample-third-party.desolint.app
Authorization: Bearer <service token signed by Desol Int.>
Accept: application/json- Each
refis an ID exactly as Desol Int.'s own API returns it: a Jira project (jira:<site>:project:<id>) or a Trello board (trello:board:<id>). Mix them freely, 1 to 100 per request. - Not project keys or board names: the same key exists on several Jira sites, and both get renamed. The
refnever changes. - Answers come back in the order asked; a repeated ref is answered once.
Response 200
{
"items": [
{
"ref": "jira:7f1c2a90-4d3e-4b21-9a55-0c2e8d11aa01:project:10042",
"found": true,
"data": { "label": "Phoenix", "note": "Client website rebuild", "updatedAt": "2026-10-20T09:14:03.000Z" }
},
{
"ref": "trello:board:60a1b2c3d4e5f60012345678",
"found": true,
"data": { "label": "Sprint", "note": "", "updatedAt": "2026-10-20T10:02:41.000Z" }
},
{
"ref": "trello:board:60a1b2c3d4e5f60012345999",
"found": false
}
]
}found: false means “this app has no label on it”. If the app cannot read its own data it answers 503 instead; it never pretends nothing exists.
How the app knows the caller is really Desol Int.
There is no shared password. Desol Int. signs a short token with its private key; this app checks it with Desol Int.'s public keys (https://auth.desolint.app/.well-known/jwks.json). The token must be meant for this app, be at most 60 seconds old, be used once, and carry this app's permission name. Code: lib/service-jwt.ts.
header: { "alg": "ES256", "typ": "service+jwt", "kid": "<key id in Desol Int.'s public key list>" }
payload: {
"iss": "https://auth.desolint.app",
"aud": "https://sample-third-party.desolint.app", // this app, and only this app
"sub": "desol:service:workbench", // which Desol Int. service is asking
"scope": "<the permission name agreed for this app>",
"iat": 1792467600,
"exp": 1792467645, // valid for at most 60 seconds
"jti": "<unique id>" // usable once
}Errors
400 invalid_request no ?ref, more than 100, or a malformed one
401 invalid_token no token, a forged/expired/reused token, or one meant for another app
403 insufficient_scope a real token that does not carry this app's permission name
503 temporarily_unavailable this app cannot read its own data right now (never answered as "nothing")
Body: { "error": { "code": "<code>", "message": "<human text, do not parse>" } }