Skip to content

Available now

Token service and workspace API ​

Available now You get your client id and secret when you connect a producer

app to your workspace in the portal (see Credentials). Everything on this page then works on its own, with no RND step per request.

The bus issues its own OAuth2 access tokens. Your app swaps its client id and secret for a short-lived token, and uses the token to publish to its workspace or to dry-run a message against it.

In the URLs below, https://api.sombus.rnd-solutions.net/v1 is the Sandbox (use the Preview's base URL from Environments there), and {t} is your workspace id.

Get a token ​

POST /v1/oauth/token: the OAuth2 client-credentials grant (RFC 6749 §4.4).

  • Body: application/x-www-form-urlencoded, with grant_type=client_credentials.

  • Client authentication, one of:

    • HTTP Basic: Authorization: Basic base64(client_id:client_secret), each part form-encoded first (RFC 6749 §2.3.1);
    • or client_id and client_secret in the body.

    Using both in one request is refused. A body client_id alongside Basic is allowed only if it is the same client.

bash
curl -s https://api.sombus.rnd-solutions.net/v1/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials
json
{ "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600 }

Tokens last one hour. Reuse a token for its whole hour and ask for a new one shortly before expires_in runs out; there is no refresh token. Fetching a token per request runs into the token URL's rate limits (see Limits). Answers are sent with Cache-Control: no-store.

Your credentials ​

  • Client id = your connection id: c followed by 12 lowercase letters and the digits 2 to 7. One connection is one app in one workspace, with one credential. A consumer app's credential reads its queue through the HTTPS pull API and can't publish; a producer's can't read a queue.
  • Client secret starts with sbs_. It is shown once, when it is issued. The bus keeps only a hash, so a lost secret can't be recovered, only replaced. Keep it out of source control; the prefix lets secret scanners spot a leak.
  • Rotation. A new secret ends every token issued before it within about 30 seconds; the previous secret can keep getting new tokens for an overlap window you choose. See Credentials.

What's in a token ​

An ES256-signed JWT. It says who you are, never what you may send: your permissions are looked up on every request, so a change or a revocation applies within about 30 seconds, whatever the token's expiry.

ClaimValue
isshttps://api.sombus.rnd-solutions.net/v1/oauth
audhttps://api.sombus.rnd-solutions.net
subyour client id (connection id)
tenantyour workspace id
orgyour organisation id
appyour app id
environmentsandbox (both hosted environments are test environments)
credential_versionYour credential's version: 1 when issued, one more with each rotation. A token of an earlier version is refused
iat, expissued at, and one hour later
jtia unique token id

The header carries alg: ES256, typ: JWT and the signing key's kid.

A token only works on the environment that issued it: aud names it, and environment must match.

Signing key (JWKS) ​

GET /v1/oauth/jwks: the public key, for clients that want to check a token themselves. You don't have to: the bus checks every token it receives.

json
{ "keys": [ { "kty": "EC", "crv": "P-256", "x": "…", "y": "…", "kid": "…", "alg": "ES256", "use": "sig" } ] }

kid is the key's RFC 7638 thumbprint. The answer may be cached for five minutes.

Publish and validate ​

Both routes take Authorization: Bearer <access token> and one SOM message as the JSON body, the same body as every other publish route (see the Bus API).

  • POST /v1/tenants/{t}/messages publishes the message.
  • POST /v1/tenants/{t}/validate is a dry run: the same checks, with your app's own permissions and your workspace's story state, but nothing is published or recorded. A message that would be accepted answers 202 with "dry_run": true.

{t} must be the workspace your credentials belong to: the tenant claim of your token.

The answers are the bus's usual ones (Verdicts and refusals): 202 accepted, 200 duplicate, 400 invalid SOM, 403 not allowed for this system_id or message_type, 409 sequence or reused message_id, 413 too large, 429 slow down, 503 retry with the same message_id.

Limits ​

The bus is for functional testing. It protects itself with a firewall and rate limits, applied before the message is read:

WhatLimitAnswer when exceeded
Each connection (your app in a workspace), on /v1/tenants/{t}/…Your workspace's quota tier, per second (see Quota tiers)429 rate.limited
Each connection, on /v1/tenants/{t}/…Your workspace's quota tier, per day (resets at midnight UTC)429 quota.exceeded
The token URL, per client using HTTP Basic30 requests in 5 minutes429 rate.limited
The token URL, per source address100 requests in 5 minutes429 rate.limited
Any route, per source address600 requests a minute429 rate.limited
The token URL20 requests a second, bursts of 40, for everyone together429 rate.limited
The signed routes /v1/tenants/{t}/iam/…, all AWS signers together50 requests a second, bursts of 100429 rate.limited
The whole API200 requests a second, bursts of 400429 rate.limited
Body size240,000 bytes413 message.too_large

Quota tiers ​

Every workspace has a quota: a tier, or limits RND sets for it. Each of its connections gets the whole allowance on its own, so one busy app never spends another's.

TierRequests a secondBursts ofRequests a day
minimal102025,000
standard2040100,000
high1002001,000,000

RND picks the tier when it approves your organisation. A vendor invited by a publisher starts on minimal. Workspaces approved before tiers applied are on standard. A vendor's connections in a house get the vendor's quota, never the house's. If you need more, ask RND: it can change your tier, or set custom limits of up to 200 requests a second, bursts of 400, and 10,000,000 a day. A change applies to your existing connections within seconds, with no new credentials.

The per-connection rows apply to bearer tokens, from this token service or from your own identity provider. Requests signed with an AWS role share the signed routes' limit instead (see Authenticate).

A 429 may carry Retry-After (seconds). Back off and retry; resending a publish with the same message_id is safe. If your testing needs more, ask RND.

A request the firewall refuses as an attack pattern answers 403request.blocked. The firewall doesn't judge SOM content: the gateway does.

Errors ​

Token request ​

Errors follow RFC 6749 §5.2: { "error": "…", "error_description": "…" }.

StatuserrorMeaningWhat to do
400invalid_requestBody is not form-encoded, malformed Basic credentials, or two authentication methods in one requestFix the request
400unsupported_grant_typegrant_type is not client_credentialsSend client_credentials
401invalid_clientUnknown client, wrong secret, a previous secret after its overlap, revoked connection, or a credential for another environment. The bus doesn't say which. With Basic, the answer carries WWW-AuthenticateCheck the id and secret, and that you call the right environment
429(bus shape, rule rate.limited)Too many token requestsReuse tokens for their hour; back off
503temporarily_unavailableThe bus could not check your credentials or sign the tokenRetry with backoff

Workspace routes ​

Violations use the usual body: { "accepted": false, "violations": [ { "rule": "…", "message": "…" } ] }.

StatusRuleMeaningWhat to do
401producer.unauthenticatedToken missing, invalid, expired, issued before a rotation, for another environment, or for a workspace your app no longer belongs toGet a new token; check the environment
403producer.not_registeredValid token, but its connection is not active: revoked or removed, or a token of the wrong kind for the route (a producer's on the pull API)Check the connection in the portal's Apps page
403tenant.mismatch{t} is not your workspaceUse the workspace id from your token's tenant claim
429rate.limited, quota.exceededOver a limit aboveBack off; retry with the same message_id
503registry.unavailableThe bus could not read your app's permissions; nothing was acceptedRetry with the same message_id

SOM is an open standard maintained by the SOM working group. This service is not endorsed by it.