All API endpoints (except /health and /auth/token) require a JWT bearer token.
Obtaining a Token
Request a token from your participant backend:
curl -X POST https://your-backend.example.com/auth/token
const response = await fetch('https://your-backend.example.com/auth/token', {
method: 'POST',
});
const { data } = await response.json();
console.log(data.token);
import requests
response = requests.post('https://your-backend.example.com/auth/token')
data = response.json()['data']
token = data['token']
Response
{
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3600,
"canton_party_id": "SenderInstitution::209fa2c...b341",
"role": "institution"
},
"meta": {
"request_id": "req_a1b2c3d4",
"timestamp": "2025-03-15T09:00:00.000Z"
}
}
Using the Token
Include the token in the Authorization header on all subsequent requests:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
https://your-backend.example.com/api/v1/orders
const response = await fetch('https://your-backend.example.com/api/v1/orders', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
response = requests.get(
'https://your-backend.example.com/api/v1/orders',
headers={'Authorization': f'Bearer {token}'},
)
JWT Claims
The token contains these claims:
| Claim | Description |
|---|
sub | Your Canton Party ID |
canton_party_id | Your Canton Party ID (same as sub) |
role | Your participant type: institution, custodian, or market-maker |
iss | Token issuer: musubi |
aud | Token audience: musubi-api |
exp | Expiration timestamp (default: 1 hour from issuance) |
Token Lifecycle
- Tokens expire after 3600 seconds (1 hour) by default
- Request a new token before the current one expires
- Expired tokens return
401 Unauthorized
The /auth/token endpoint is a development convenience. In production, tokens will be issued by an external identity provider (e.g., Keycloak, Auth0) integrated with your organization’s SSO.
Verifying Your Identity
Use the /api/v1/whoami endpoint to confirm your backend’s party identity, participant id, and schema version:
curl https://your-backend.example.com/api/v1/whoami
{
"data": {
"party_id": "Institution::209fa2c...b341",
"operator_party_id": "Musubi::1220xyz...",
"role": "institution",
"participant_id": "PAR::institution::1220xyz...",
"schema_version": "v2"
}
}
The schema_version field is pinned at "v2" post-ADR-0011 PR-03 — clients MUST gate on this value so any future breaking shape change is detectable, not silent. participant_id is the Canton participant id discovered from the Ledger API at boot; it is the empty string "" in sandbox / localnet mode (no MUSUBI_LEDGER_API_JWT).