Credentials API
The Credentials API provides secure, on-demand access to decrypted service credentials. Credentials are stored encrypted with AWS KMS envelope encryption and only decrypted in-memory when explicitly retrieved. Every retrieval is audit-logged as credential.retrieve for compliance and security monitoring.
Credentials are sensitive secrets (API keys, OAuth tokens, passwords). They are returned in plaintext over TLS. Ensure your application handles them securely — do not log them, store them in plaintext, or expose them to untrusted contexts.
All endpoints require an Authorization: Bearer sk_live_... header with a valid operator API key or team member API key. Member keys are subject to allowed_connections restrictions.
Get Credential by Provider
GET /v1/credentials/:provider
Retrieve the decrypted credential for a connected service, identified by its provider key (e.g., slack, openai,custom_internal_crm). If you have multiple connections to the same provider, use the /by-connection/:connectionId endpoint instead.
Request Example
curl https://api.getstack.run/v1/credentials/openai \
-H "Authorization: Bearer sk_live_op_abc123"Response — 200 OK (Single-field credential)
For services connected with a single API key or token, the response includes a credential string field:
{
"provider": "openai",
"credential": "sk-proj-abc123def456ghi789jkl012mno345"
}Response — 200 OK (Multi-field credential)
For services connected with multiple credential fields (e.g., custom services with username + password, or host + port + key), the response includes a credentials object:
{
"provider": "custom_sftp_server",
"credentials": {
"host": "sftp.example.com",
"username": "stack-agent",
"password": "s3cur3p4ss",
"port": "22"
}
}Response — 200 OK (OAuth credential)
For OAuth-connected services, the credential is the access token granted during the OAuth flow:
{
"provider": "slack",
"credential": "xoxb-1234567890-1234567890123-abc123def456ghi789jkl012"
}Error Responses
- 401 Unauthorized — Missing or invalid API key.
- 403 Forbidden — Member key does not have access to this provider. The provider is not listed in the member's allowed_connections.
- 404 Not Found — No connection exists for this provider under your account.
- 409 Conflict — Multiple connections exist for this provider. Use /by-connection/:connectionId instead.
Get Credential by Connection ID
GET /v1/credentials/by-connection/:connectionId
Retrieve a decrypted credential by connection ID. This is the recommended approach when an operator has multiple connections to the same provider (e.g., two separate Slack workspaces or multiple AWS accounts).
Request Example
curl https://api.getstack.run/v1/credentials/by-connection/conn_8mR4xK9wN2 \
-H "Authorization: Bearer sk_live_op_abc123"Response — 200 OK
{
"provider": "slack",
"connection_id": "conn_8mR4xK9wN2",
"credential": "xoxb-1234567890-1234567890123-abc123def456ghi789jkl012"
}Error Responses
- 401 Unauthorized — Missing or invalid API key.
- 403 Forbidden — Member key does not have access to this connection.
- 404 Not Found — Connection ID does not exist or belongs to a different operator.
Member Key Restrictions
Team member API keys can be configured with an allowed_connections list that restricts which service credentials they can access. When a member key attempts to retrieve a credential for a provider not in their allow-list, the API returns a 403 Forbidden error.
Example: Member key with restricted access
# Member key only has access to "slack" and "github"
curl https://api.getstack.run/v1/credentials/openai \
-H "Authorization: Bearer sk_live_mem_xyz789"Response — 403 Forbidden
{
"error": "forbidden",
"message": "This API key does not have access to the 'openai' provider. Contact your operator to update your allowed connections."
}Operators and admins can manage member access restrictions via the PATCH /v1/team/members/:id endpoint or through the dashboard team settings.
Security Model
The Credentials API implements multiple layers of security to protect stored secrets:
Encryption at Rest
- All credentials are encrypted using AWS KMS envelope encryption before storage.
- A unique data encryption key (DEK) is generated per credential.
- The DEK is encrypted with a KMS master key and stored alongside the ciphertext.
- Plaintext DEKs are never persisted — they exist only in memory during encrypt/decrypt operations.
Encryption in Transit
- All API communication is over TLS 1.2+.
- Decrypted credentials are returned in the response body and immediately wiped from server memory.
- No caching of decrypted credential values on the server side.
Audit Trail
Every credential retrieval is logged in the append-only audit log with the following details:
{
"event": "credential.retrieve",
"operator_id": "op_abc123",
"actor_type": "member",
"actor_id": "mem_3kW7xR9mN4",
"provider": "openai",
"connection_id": "conn_2pK7mW4xR9",
"timestamp": "2026-04-15T10:30:00.000Z",
"ip_address": "203.0.113.42",
"chain_hash": "sha256:e5f6g7h8..."
}The audit log is hash-chained — each entry includes a hash of the previous entry, making tampering detectable. Audit entries cannot be updated or deleted.
Common Usage Patterns
Agent Workflow: Retrieve and Use
The typical pattern is for an agent to retrieve a credential just before making an API call, use it immediately, and discard it:
// Agent retrieves credential on-demand
const response = await fetch('https://api.getstack.run/v1/credentials/openai', {
headers: { 'Authorization': 'Bearer ' + process.env.STACK_API_KEY }
});
const { credential } = await response.json();
// Use it immediately
const completion = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${credential}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
})
});
// credential goes out of scope — do not persist itMCP Tool: stack_get_credential
Agents connected via MCP can use the stack_get_credential tool to retrieve credentials without making direct HTTP calls:
{
"tool": "stack_get_credential",
"arguments": {
"provider": "slack"
}
}The MCP tool wraps the same API endpoint and enforces the same access controls. Audit logging records the MCP tool invocation as the retrieval source.