Credentials
Stateway provides an encrypted credential store so you can reference secrets — API tokens, access keys, passwords — in process definitions without embedding them in plaintext.
Why not put secrets directly in BPMN
Embedding secrets directly in task headers is dangerous:
<!-- ❌ Never do this -->
<stateway:header key="headers" value='{"Authorization": "Bearer sk_live_abc123..."}' />
The value is stored in plaintext in the source column of process_definitions, appears in XML exports (GET /definitions/:key/xml), and in any database dump. A definition leak becomes a credential leak.
Creating a credential
Request:
curl -X POST https://api.stateway.io/v1/credentials \
-H "X-API-Key: sw_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "payment_api_token",
"value": "sk_live_abc123...",
"description": "Payment gateway API token"
}'
Response:
{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z"
}
}
The value is encrypted with AES-256-GCM before being persisted. The value is never returned by the API after creation. To replace it, use PATCH.
Rules for name:
- Lowercase letters, digits, and underscores only
- Must start with a lowercase letter
- Maximum 64 characters
- Examples:
payment_api_token,fraud_service_key,internal_auth
Listing credentials
Returns metadata only — values are never included.
Request:
curl https://api.stateway.io/v1/credentials \
-H "X-API-Key: sw_live_..."
Response:
{
"data": [
{
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-01T12:00:00.000Z"
}
]
}
Requires the credentials:read or admin scope.
Getting a credential by name
Request:
curl https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..."
Response:
{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-01T12:00:00.000Z"
}
}
Requires the credentials:read or admin scope.
Using credentials in service tasks
Reference a credential with the {{credentials.name}} syntax anywhere in taskHeaders:
<bpmn:serviceTask id="callPaymentApi" name="Charge Payment">
<bpmn:extensionElements>
<stateway:taskDefinition type="http" />
<stateway:taskHeaders>
<stateway:header key="url" value="https://api.payment.com/charge" />
<stateway:header key="method" value="POST" />
<stateway:header key="headers" value='{"Authorization": "Bearer {{credentials.payment_api_token}}"}' />
</stateway:taskHeaders>
</bpmn:extensionElements>
</bpmn:serviceTask>
The engine resolves the reference at execution time: the decrypted value exists only in memory during token execution and is never written to logs, the audit log, or webhook payloads.
Rotating a credential
To replace the value without touching any process definition that references it:
Request:
curl -X PATCH https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..." \
-H "Content-Type: application/json" \
-d '{ "value": "sk_live_xyz456..." }'
Response:
{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-13T09:00:00.000Z"
}
}
All instances started after the rotation will use the new value automatically. Instances already in progress that have not yet reached the service task will also pick up the new value.
You can also update the description without changing the value:
Request:
curl -X PATCH https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..." \
-H "Content-Type: application/json" \
-d '{ "description": "Payment gateway token (renewed May 2026)" }'
Response:
{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway token (renewed May 2026)",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-13T09:05:00.000Z"
}
}
Deleting a credential
Request:
curl -X DELETE https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..."
Returns 204 No Content. The deletion is soft — the credential is marked as deleted and no longer resolvable by the engine. Any process that references {{credentials.payment_api_token}} after deletion will fail at the service task with a credential resolution error.
Required scopes
| Operation | Required scope |
|---|---|
GET /v1/credentials | credentials:read or admin |
GET /v1/credentials/:name | credentials:read or admin |
POST /v1/credentials | credentials:write or admin |
PATCH /v1/credentials/:name | credentials:write or admin |
DELETE /v1/credentials/:name | credentials:write or admin |
Security limitations
The current security model does not protect against:
- Direct access to the application process (anyone who can exec into the container can decrypt)
- Compromise of the Kubernetes cluster (K8s secrets would be accessible)
Stateway encrypts credentials with a platform-managed key. If that key is lost, rotated unexpectedly, or compromised, stored values may be permanently and irrecoverably lost.
Always keep independent, secure copies of your original credentials. The Credential Endpoint is a runtime reference mechanism — not a primary secret store.