Authentication
All Ditio API endpoints require authentication. The API uses OAuth 2.0
client credentials: you exchange a client_id and client_secret for a
short-lived bearer token, and send that token with every request.
Environments
Section titled “Environments”Ditio has two environments. Credentials are per-environment — a client created in production does not work in test, and vice versa.
| Production | Test | |
|---|---|---|
| API | https://core-api.ditio.app/core | https://core-api.ditio.dev/core |
| Reporting API | https://core-api.ditio.app/reporting | https://core-api.ditio.dev/reporting |
| Identity (tokens) | https://identity.ditio.app | https://identity.ditio.dev |
All code samples in this documentation use environment variables so you can switch environments in one place — and they default to test:
# Test (default for all examples)export DITIO_API_BASE="https://core-api.ditio.dev/core"export DITIO_REPORTING_BASE="https://core-api.ditio.dev/reporting"export DITIO_IDENTITY_BASE="https://identity.ditio.dev"
# Production — only after verifying in test# export DITIO_API_BASE="https://core-api.ditio.app/core"# export DITIO_REPORTING_BASE="https://core-api.ditio.app/reporting"# export DITIO_IDENTITY_BASE="https://identity.ditio.app"Creating API credentials
Section titled “Creating API credentials”Any Ditio administrator can create API credentials self-service:
- Log in to Ditio Web
- Go to Company Setup (Oppsett) → Integration
- Click Create new API client and give it a descriptive name (e.g. “ERP Integration”, “Power BI”)
- The system generates a
client_idandclient_secret
Create separate clients for separate use cases so they can be disabled or deleted independently. Disabling a client immediately revokes its access.
Obtaining a Token
Section titled “Obtaining a Token”Exchange your credentials for a bearer token at the identity server:
curl -X POST "$DITIO_IDENTITY_BASE/connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "scope=ditioapiv3"Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "expires_in": 1800, "token_type": "Bearer", "scope": "ditioapiv3"}Scopes
Section titled “Scopes”| Scope | Grants access to |
|---|---|
ditioapiv3 | Core + Integration API — use this for most integrations |
masstransportapiv1 | Mass Transport API (machine integration) |
reportingapiv1 | Reporting / Data Extraction API |
Request multiple scopes in one token by separating them with a space:
scope=ditioapiv3 reportingapiv1.
Using the Token
Section titled “Using the Token”Include the access token in the Authorization header of every API request:
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ "$DITIO_API_BASE/api/v4/integration/projects"Token Expiry
Section titled “Token Expiry”Tokens are short-lived — about 30 minutes by default (configurable per
client, up to 24 hours). Read expires_in from the token response, cache the
token, and refresh it shortly before it lapses. Your integration should also
handle 401 Unauthorized responses by requesting a new token. Never request
a fresh token per API call.
// Cache the token; only fetch a new one shortly before it expires.private static string _token;private static DateTime _tokenExpiresUtc = DateTime.MinValue;
async Task<string> GetTokenAsync(HttpClient http){ // Refresh ~1 minute early so a token never expires mid-request. if (_token is not null && DateTime.UtcNow < _tokenExpiresUtc.AddMinutes(-1)) return _token;
var identityBase = Environment.GetEnvironmentVariable("DITIO_IDENTITY_BASE") ?? "https://identity.ditio.dev"; var response = await http.PostAsync( $"{identityBase}/connect/token", new FormUrlEncodedContent(new Dictionary<string, string> { ["grant_type"] = "client_credentials", ["client_id"] = clientId, ["client_secret"] = clientSecret, ["scope"] = "ditioapiv3", })); response.EnsureSuccessStatusCode();
var token = await response.Content.ReadFromJsonAsync<TokenResponse>(); _token = token!.access_token; _tokenExpiresUtc = DateTime.UtcNow.AddSeconds(token.expires_in); return _token;}
private record TokenResponse(string access_token, int expires_in, string token_type);Long-lived tokens from the UI
Section titled “Long-lived tokens from the UI”If you can’t run the token flow (e.g. a BI tool that only accepts a static token), an administrator can generate a longer-lived token directly in the Ditio Web UI on the integration page (these are audited). Each API client can be disabled or deleted at any time from the same page, immediately revoking access.
Security Best Practices
Section titled “Security Best Practices”- Never expose your Client Secret in client-side code or version control
- Store credentials in environment variables or a secrets manager
- Rotate your Client Secret periodically
- Use the minimum required scopes for your integration
- Implement token caching to avoid unnecessary token requests