Developer cookbook
M2M cookbook - server-to-server API keys.
Server-side API access uses ak_-prefixed keys minted through api-keys-admin.html. Every call carries Authorization: Bearer ak_... over TLS, is per-tenant rate-limited, and can be revoked from the admin UI in one click. Tenants that also expose European Digital Identity Wallet sign-in use the same key surface for background jobs.
OIDC sign-in cookbookJWT validation cookbookWebhooks cookbookCompliance archive cookbookRealtime events cookbookAPI docsMint an API key
Framework matrix (Flow A - API keys)
| Framework / language | Library | Recipe | Snippet |
|---|---|---|---|
| Node.js | axios | Open | m2m-api-key-nodejs.js |
| Python | requests | Open | m2m-api-key-python.py |
| PHP | curl | Open | m2m-api-key-php.php |
| cURL | plain shell | Open | m2m-api-key-curl.sh |
| Java | java.net.http | Open | m2m-api-key-java.java |
| Go | net/http | Open | m2m-api-key-go.go |
| .NET | HttpClient | Open | m2m-api-key-dotnet.cs |
Node.js Recipe
axios. Download raw .js
// Server-to-server call to a CodeB tenant using an API key.
// European Digital Identity Wallet claims presented at sign-in are
// out-of-band from M2M; API keys are for background jobs.
// [m2m-cookbook 2026-07-23]
// npm install axios
//
// Mint the key at https://<CODEB_TENANT_HOST>/api-keys-admin.html
// Keys have the form ak_XXXXXXXXXXXXXXXX and MUST travel over TLS.
const axios = require('axios');
const TENANT = 'https://<CODEB_TENANT_HOST>';
const API_KEY = process.env.CODEB_API_KEY; // ak_...
const api = axios.create({
baseURL: TENANT,
timeout: 15000,
headers: { Authorization: 'Bearer ' + API_KEY }
});
async function listUsers(){
const r = await api.get('/api.ashx?action=users.list');
return r.data;
}
listUsers().then(u => console.log(u.length + ' users'));
Python Recipe
requests. Download raw .python
# Server-to-server call to a CodeB tenant using an API key.
# European Digital Identity Wallet claims presented at sign-in are
# out-of-band from M2M; API keys are for background jobs.
# [m2m-cookbook 2026-07-23]
# pip install requests
#
# Mint the key at https://<CODEB_TENANT_HOST>/api-keys-admin.html
# Keys have the form ak_XXXXXXXXXXXXXXXX and MUST travel over TLS.
import os, requests
TENANT = "https://<CODEB_TENANT_HOST>"
API_KEY = os.environ["CODEB_API_KEY"] # ak_...
sess = requests.Session()
sess.headers["Authorization"] = f"Bearer {API_KEY}"
def list_users():
r = sess.get(f"{TENANT}/api.ashx?action=users.list", timeout=15)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
print(len(list_users()), "users")
PHP Recipe
curl. Download raw .php
<?php
// Server-to-server call to a CodeB tenant using an API key.
// European Digital Identity Wallet claims are out-of-band; API keys are
// for background jobs.
// [m2m-cookbook 2026-07-23]
//
// Mint the key at https://<CODEB_TENANT_HOST>/api-keys-admin.html
// Keys have the form ak_XXXXXXXXXXXXXXXX and MUST travel over TLS.
const TENANT = 'https://<CODEB_TENANT_HOST>';
$apiKey = getenv('CODEB_API_KEY'); // ak_...
function api_get(string $path, string $apiKey): array {
$ch = curl_init(TENANT . $path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
CURLOPT_TIMEOUT => 15,
]);
$body = curl_exec($ch);
if ($body === false) throw new RuntimeException(curl_error($ch));
return json_decode($body, true);
}
$users = api_get('/api.ashx?action=users.list', $apiKey);
printf("%d users\n", count($users));
cURL Recipe
plain shell. Download raw .bash
#!/usr/bin/env bash
# Server-to-server call to a CodeB tenant using an API key.
# European Digital Identity Wallet claims are out-of-band; API keys are
# for background jobs.
# [m2m-cookbook 2026-07-23]
#
# Mint the key at https://<CODEB_TENANT_HOST>/api-keys-admin.html
# Keys have the form ak_XXXXXXXXXXXXXXXX and MUST travel over TLS.
set -euo pipefail
TENANT="${CODEB_TENANT:-https://<CODEB_TENANT_HOST>}"
API_KEY="${CODEB_API_KEY:?set CODEB_API_KEY=ak_...}"
curl -sSf \
-H "Authorization: Bearer ${API_KEY}" \
"${TENANT}/api.ashx?action=users.list" | jq .
Java Recipe
java.net.http. Download raw .java
// Server-to-server call to a CodeB tenant using an API key.
// European Digital Identity Wallet claims are out-of-band; API keys are
// for background jobs.
// [m2m-cookbook 2026-07-23]
//
// Mint the key at https://<CODEB_TENANT_HOST>/api-keys-admin.html
// Keys have the form ak_XXXXXXXXXXXXXXXX and MUST travel over TLS.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class CodebApiKeyClient {
private static final String TENANT = "https://<CODEB_TENANT_HOST>";
private static final String API_KEY = System.getenv("CODEB_API_KEY");
public static void main(String[] args) throws Exception {
HttpClient c = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10)).build();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(TENANT + "/api.ashx?action=users.list"))
.header("Authorization", "Bearer " + API_KEY)
.timeout(Duration.ofSeconds(15))
.GET().build();
HttpResponse<String> r = c.send(req, HttpResponse.BodyHandlers.ofString());
if (r.statusCode() != 200) throw new RuntimeException("HTTP " + r.statusCode());
System.out.println(r.body());
}
}
Go Recipe
net/http. Download raw .go
// Server-to-server call to a CodeB tenant using an API key.
// European Digital Identity Wallet claims are out-of-band; API keys are
// for background jobs.
// [m2m-cookbook 2026-07-23]
//
// Mint the key at https://<CODEB_TENANT_HOST>/api-keys-admin.html
// Keys have the form ak_XXXXXXXXXXXXXXXX and MUST travel over TLS.
package main
import (
"fmt"
"io"
"net/http"
"os"
"time"
)
const Tenant = "https://<CODEB_TENANT_HOST>"
func main() {
apiKey := os.Getenv("CODEB_API_KEY")
if apiKey == "" {
fmt.Fprintln(os.Stderr, "set CODEB_API_KEY=ak_...")
os.Exit(1)
}
client := &http.Client{Timeout: 15 * time.Second}
req, _ := http.NewRequest("GET", Tenant+"/api.ashx?action=users.list", nil)
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := client.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
.NET Recipe
HttpClient. Download raw .csharp
// Server-to-server call to a CodeB tenant using an API key.
// European Digital Identity Wallet claims are out-of-band; API keys are
// for background jobs.
// [m2m-cookbook 2026-07-23]
//
// Mint the key at https://<CODEB_TENANT_HOST>/api-keys-admin.html
// Keys have the form ak_XXXXXXXXXXXXXXXX and MUST travel over TLS.
using System.Net.Http.Headers;
const string Tenant = "https://<CODEB_TENANT_HOST>";
string apiKey = Environment.GetEnvironmentVariable("CODEB_API_KEY")
?? throw new InvalidOperationException("set CODEB_API_KEY=ak_...");
using var http = new HttpClient { BaseAddress = new Uri(Tenant),
Timeout = TimeSpan.FromSeconds(15) };
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", apiKey);
var body = await http.GetStringAsync("/api.ashx?action=users.list");
Console.WriteLine(body);
Test it
Round-trip check: curl -sSf -H 'Authorization: Bearer ak_...' https://<host>/api.ashx?action=ping. Non-200 responses include an error code and a human-readable hint.
Security notes
- Keys travel over TLS only. Any plaintext channel is rejected.
- Per-tenant rate limits return HTTP 429 with a
Retry-Afterheader; backoff and resume. - Rotation is manual from api-keys-admin.html; revocation is instant (in-memory cache invalidated within one heartbeat).
- Each request path emits inline anomaly detection and integrity checks with loud diagnostics; do not disable a key from the admin UI while it is mid-request without expecting a 401 on the next call.
FAQ
See structured answers in the schema block above.