Get started
Authenticate and call DevKit Gateway V5 endpoints.
Get started with Gateway V5
All signed V5 endpoints use a project API key and its Gateway secret. The API key determines the owning project and organization on the server. Do not send project_id, organization_id, or similar authority fields to select data from another project.
Keep secrets private
Never put a Gateway secret in browser code, a mobile app, source control, logs, or support tickets. Store it only in a server-side secret manager.
Required headers
Every signed request must include these headers:
| Header | Value |
|---|---|
api-key | Your project API key |
timestamp | Current Unix timestamp in seconds |
hash-signature | Hex HMAC-SHA256 signature described below |
Idempotency-Key is reserved for future write endpoints. Do not send it to the current read-only GET endpoints.
Sign the exact request
V5 uses the DK-HMAC-V5-1 profile. Sign the exact bytes below, in this order:
DK-HMAC-V5-1\n
HTTP_METHOD\n
REQUEST_TARGET\n
TIMESTAMP\n
IDEMPOTENCY_KEY\n
RAW_BODYHTTP_METHODis uppercase, for exampleGET.REQUEST_TARGETbegins with/and includes the query string exactly as sent, for example/api/v5/requests?limit=20.TIMESTAMPis the same value sent in thetimestampheader.IDEMPOTENCY_KEYis empty for the current V5GETendpoints.RAW_BODYis the unmodified request body. It is empty forGETrequests.- The timestamp must be within the server’s allowed clock skew (five minutes by default).
The server never uses a client-supplied project or organization identifier as authority. A valid key always resolves to its own project. An unknown key, wrong secret, stale timestamp, or invalid signature receives the same safe 401 VC_UNAUTHORIZED response so secrets cannot be guessed.
Node.js example
import crypto from 'node:crypto';
const baseUrl = process.env.DEVKIT_BASE_URL;
const apiKey = process.env.DEVKIT_V5_API_KEY;
const secret = process.env.DEVKIT_V5_SECRET;
const method = 'GET';
const target = '/api/v5/keys';
const timestamp = Math.floor(Date.now() / 1000).toString();
const rawBody = '';
const canonical = [
'DK-HMAC-V5-1',
method,
target,
timestamp,
'',
rawBody,
].join('\n');
const signature = crypto
.createHmac('sha256', secret)
.update(canonical, 'utf8')
.digest('hex');
const response = await fetch(`${baseUrl}${target}`, {
method,
headers: {
'api-key': apiKey,
timestamp,
'hash-signature': signature,
},
});
console.log(await response.json());Postman setup
Create these collection variables (or environment variables):
| Variable | Initial value |
|---|---|
base_url | Your DevKit base URL, such as http://127.0.0.1:5000 |
v5_api_key | Your V5 project API key |
v5_secret | The matching Gateway secret |
Add the following collection-level Pre-request Script to the V5 folder. Individual requests inherit it.
const method = pm.request.method.toUpperCase();
const timestamp = Math.floor(Date.now() / 1000).toString();
const requestUrl = pm.variables.replaceIn(pm.request.url.toString());
const url = new URL(requestUrl);
const target = `${url.pathname}${url.search}`;
const rawBody = pm.request.body?.raw || '';
const retryKey = '';
const canonical = [
'DK-HMAC-V5-1',
method,
target,
timestamp,
retryKey,
rawBody,
].join('\n');
const apiKey = pm.variables.get('v5_api_key');
const secret = pm.variables.get('v5_secret');
const signature = CryptoJS.HmacSHA256(canonical, secret).toString(CryptoJS.enc.Hex);
pm.request.headers.upsert({ key: 'api-key', value: apiKey });
pm.request.headers.upsert({ key: 'timestamp', value: timestamp });
pm.request.headers.upsert({ key: 'hash-signature', value: signature });
pm.request.headers.remove('secret-key');
pm.request.headers.remove('key');The GET /api/v5/openapi.json request is public and does not need this script.
Endpoint behavior
| Endpoint | Expected successful result |
|---|---|
GET /api/v5/keys | data.current shows the active key metadata; data.overlap is populated only during a rotation overlap. Secrets are never returned. |
GET /api/v5/usage | Returns organization-level usage that belongs to the key’s organization. Pay-as-you-go fields appear only for pay-as-you-go organizations; plan usage can explicitly be unavailable. |
GET /api/v5/limits | Returns known organization entitlements. Missing providers are represented as unavailable, never invented quotas. |
GET /api/v5/requests | Returns safe request diagnostics. If diagnostics are not configured, returns { "availability": "unavailable", "items": [] }. |
Successful signed responses use a { "data": ... } envelope and include:
| Response header | Meaning |
|---|---|
X-Gateway-Request-ID | Support-safe ID to share with DevKit support. |
X-Gateway-Requests-Used | Informational request count, or unavailable when its cache is unavailable. It is not a quota. |
Errors
| Status | Code | Meaning |
|---|---|---|
401 | VC_UNAUTHORIZED | API key, secret/signature, or timestamp was not accepted. Confirm the key/secret pairing, system clock, exact target, and raw body. |
403 | VC_GATEWAY_PROJECT_SUSPENDED | The authenticated project is suspended. |
404 | VC_GATEWAY_DISABLED | Gateway V5 is disabled in this environment. |
404 | VC_RESOURCE_NOT_FOUND | The requested V5 resource does not exist. |
503 | VC_GATEWAY_UNAVAILABLE | A required downstream service is temporarily unavailable. Retry later. |
Test checklist
- Call
/api/v5/openapi.json; expect200while V5 is enabled. - Send
GET /api/v5/keysusing the V5 folder script; expect200and adataenvelope without a secret. - Change
v5_secrettemporarily; expect401 VC_UNAUTHORIZED. - Set a timestamp more than five minutes old; expect
401 VC_UNAUTHORIZED. - Alter the request query after the signature is created; expect
401 VC_UNAUTHORIZED. - Call
/api/v5/requests;availability: unavailablewith an emptyitemsarray is valid until diagnostics are configured.