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.

Framework matrix (Flow A - API keys)

Framework / languageLibraryRecipeSnippet
Node.jsaxiosOpenm2m-api-key-nodejs.js
PythonrequestsOpenm2m-api-key-python.py
PHPcurlOpenm2m-api-key-php.php
cURLplain shellOpenm2m-api-key-curl.sh
Javajava.net.httpOpenm2m-api-key-java.java
Gonet/httpOpenm2m-api-key-go.go
.NETHttpClientOpenm2m-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

FAQ

See structured answers in the schema block above.