Appearance
Keys & OAuth API
API endpoints for managing API keys and OAuth tokens.
List Keys
Get all stored API keys and OAuth tokens.
http
GET /keysExample:
bash
curl "https://api.universalapi.co/keys" \
-H "Authorization: Bearer $BEARER_TOKEN"Response:
json
{
"success": true,
"data": {
"userId": "user-id",
"count": 2,
"keys": [
{
"keyName": "openai",
"keyValue": "sk-xxx...",
"description": "OpenAI API key",
"status": "active",
"createdAt": 1736734800000
},
{
"keyName": "google_oauth",
"keyValue": "ya29.xxx...",
"secretKeyName": "refresh_token",
"secretKeyValue": "1//0xxx...",
"description": "Google OAuth tokens",
"status": "active",
"additionalFields": {
"token_type": "Bearer",
"expires_at": 1736738400000,
"scope": "https://www.googleapis.com/auth/drive"
}
}
]
}
}Create Key
Store a new API key.
http
POST /keys/createRequired Fields:
| Field | Type | Description |
|---|---|---|
newKey | string | Key name (e.g., "openai", "serpapi") |
newKeyValue | string | The API key value |
Optional Fields:
| Field | Type | Description |
|---|---|---|
newKeyDescription | string | Description of the key |
newSecretKey | string | Secondary secret name |
newSecretKeyValue | string | Secondary secret value |
Example:
bash
curl -X POST "https://api.universalapi.co/keys/create" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BEARER_TOKEN" \
-d '{
"newKey": "openai",
"newKeyValue": "sk-xxx...",
"newKeyDescription": "OpenAI API key for GPT-4"
}'Response:
json
{
"success": true,
"data": {
"message": "API key for openai created successfully",
"keyInfo": {
"keyName": "openai",
"status": "active",
"createdAt": 1736734800000
}
}
}Delete Key
Remove a stored API key.
http
DELETE /keys/deleteExample:
bash
curl -X DELETE "https://api.universalapi.co/keys/delete" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BEARER_TOKEN" \
-d '{"keyName": "openai"}'Alternative (query parameter):
bash
curl -X DELETE "https://api.universalapi.co/keys/delete?keyName=openai" \
-H "Authorization: Bearer $BEARER_TOKEN"OAuth Endpoints
Start OAuth Flow
Initiate OAuth authorization for a provider.
http
GET /oauth/{provider}/authorizeSupported Providers: google, microsoft, github
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
userId | string | Your user ID |
redirect_uri | string | Where to redirect after auth |
Example:
GET /oauth/google/authorize?userId=user-id&redirect_uri=https://universalapi.co/oauth/callbackReturns a URL to redirect the user to the provider's consent screen.
OAuth Callback
Handles the OAuth callback from the provider.
http
GET /oauth/{provider}/callbackThis is called automatically by the OAuth provider. Do not call directly.
Refresh OAuth Token
Manually refresh an OAuth access token.
http
POST /oauth/{provider}/refreshBody:
json
{
"refreshToken": "1//0xxx..."
}Example:
bash
curl -X POST "https://api.universalapi.co/oauth/google/refresh" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BEARER_TOKEN" \
-d '{"refreshToken": "1//0xxx..."}'Response:
json
{
"success": true,
"data": {
"message": "Token refreshed successfully",
"provider": "google",
"token_info": {
"access_token_prefix": "ya29.a0...",
"token_type": "Bearer",
"expires_in": 3599,
"expires_at": 1736738400000
}
}
}Revoke OAuth Token
Revoke an OAuth token.
http
POST /oauth/{provider}/revokeBody:
json
{
"token": "ya29.xxx..."
}Example:
bash
curl -X POST "https://api.universalapi.co/oauth/google/revoke" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $BEARER_TOKEN" \
-d '{"token": "ya29.xxx..."}'Access Tokens
Access tokens provide programmatic API access. There are two types:
User Tokens (uapi_ut_*)
Full-access tokens that inject all your global third-party keys at runtime.
Create User Token
http
POST /user/token/createjson
{
"tokenName": "My App Token",
"tokenType": "user",
"description": "Token for my application",
"creditLimit": 10000
}Response:
json
{
"data": {
"tokenId": "tok-abc123",
"token": "uapi_ut_abc123...",
"tokenType": "user",
"tokenName": "My App Token",
"creditLimit": 10000,
"creditUsed": 0
}
}Role Tokens (uapi_rt_*)
Scoped tokens that carry their own embedded key set. Only the attached keys are injected at runtime — not your global keys.
Create Role Token
http
POST /user/token/createjson
{
"tokenName": "AWS Only",
"tokenType": "role",
"keys": {
"aws_access_key_id": "AKIA...",
"aws_secret_access_key": "wJal...",
"aws_region": "us-east-1"
}
}Response:
json
{
"data": {
"tokenId": "tok-xyz789",
"token": "uapi_rt_xyz789...",
"tokenType": "role",
"tokenName": "AWS Only",
"keyCount": 3,
"keyNames": ["aws_access_key_id", "aws_secret_access_key", "aws_region"]
}
}WARNING
Key values are never returned after creation. Only key names are visible in GET responses.
Update Role Token Keys
http
PUT /user/token/updatejson
{
"tokenId": "tok-xyz789",
"keys": {
"aws_access_key_id": "AKIA-new...",
"aws_secret_access_key": "wJal-new...",
"aws_region": "us-west-2"
}
}Common Token Operations
| Operation | Endpoint | Method |
|---|---|---|
| Create | POST /user/token/create | tokenType: "user" or "role" |
| List all | GET /user/token/list | Optional ?type=role filter |
| Get details | GET /user/token/{tokenId} | Returns key names (not values) for role tokens |
| Update | PUT /user/token/update | Update name, description, credit limit, or keys |
| Revoke | DELETE /user/token/revoke | Body: { "tokenId": "..." } |
| Regenerate | POST /user/token/{tokenId}/regenerate | New token value, same settings |
Author Key Injection
Authors can attach a role token to their resources using the authorRoleToken field:
http
POST /mcp-server/createjson
{
"serverName": "my-textract-server",
"sourceCode": "...",
"authorRoleToken": "uapi_rt_my_role_token",
"authorPricing": { "pricePerInvocation": 0.05 }
}At runtime, the author's role token keys are resolved and merged with the invoking user's keys. The invoking user's keys take priority on conflicts.
Using Keys at Runtime
When you execute any resource (action, agent, or MCP server), your stored API keys are automatically injected into the runtime environment. This means resource authors can write code that uses the invoking user's keys without any manual configuration.
Key Structure
Each key is a dict with these fields:
| Field | Type | Description |
|---|---|---|
keyName | string | The key name (e.g., "openai") |
keyValue | string | The primary key value |
description | string | Description of the key |
secretKeyName | string | Secondary secret name (optional) |
secretKeyValue | string | Secondary secret value (optional) |
additionalFields | dict | Extra metadata (optional) |
In Actions
Action code receives keys via parameters['keys']:
python
def handler(parameters):
# Check if key exists
keys = parameters.get('keys', {})
if 'openai' not in keys:
return {"error": "OpenAI key not configured. Add it in Credentials → Third-Party Keys."}
# Access the key
api_key = keys['openai']['keyValue']
# Use it
import json
from urllib.request import Request, urlopen
req = Request(
"https://api.openai.com/v1/chat/completions",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
},
data=json.dumps({
"model": "gpt-4",
"messages": [{"role": "user", "content": "Hello!"}]
}).encode()
)
response = json.loads(urlopen(req).read())
return {"result": response}In Strands Agents
Agent code can access keys in two ways:
1. user_keys dict (injected into sandbox namespace):
python
from strands import Agent, tool
from strands.models import BedrockModel
@tool
def call_openai(prompt: str) -> str:
"""Call OpenAI API using the user's stored API key."""
import json
from urllib.request import Request, urlopen
# user_keys is automatically available in the agent namespace
api_key = user_keys.get('openai', {}).get('keyValue')
if not api_key:
return "Error: No OpenAI key found. Add it in Credentials → Third-Party Keys."
req = Request(
"https://api.openai.com/v1/chat/completions",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
},
data=json.dumps({
"model": "gpt-4",
"messages": [{"role": "user", "content": prompt}]
}).encode()
)
return json.loads(urlopen(req).read())['choices'][0]['message']['content']
def create_agent():
agent = Agent(
model=BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0"),
tools=[call_openai],
system_prompt="You can call OpenAI models using the user's API key."
)
return agent, []2. UAPI_KEYS_JSON environment variable (JSON-serialized full keys dict):
python
import os, json
keys = json.loads(os.environ.get('UAPI_KEYS_JSON', '{}'))
openai_key = keys.get('openai', {}).get('keyValue')
stripe_key = keys.get('stripe', {}).get('keyValue')In MCP Servers
MCP server source code receives the full user context (including keys) via the userContext parameter passed to createMcpServer():
javascript
function createMcpServer(userContext) {
const keys = userContext?.keys || {};
const openaiKey = keys.openai?.keyValue;
// Use keys in tool implementations
server.tool("call-openai", { prompt: z.string() }, async ({ prompt }) => {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${openaiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "gpt-4",
messages: [{ role: "user", content: prompt }]
})
});
return { content: [{ type: "text", text: JSON.stringify(await response.json()) }] };
});
}OAuth Token Structure
When Google OAuth is connected:
python
keys["google_oauth"] = {
"keyName": "google_oauth",
"keyValue": "ya29.xxx...", # Access token
"secretKeyName": "refresh_token",
"secretKeyValue": "1//0xxx...", # Refresh token
"additionalFields": {
"token_type": "Bearer",
"expires_at": 1736738400000,
"scope": "https://www.googleapis.com/auth/drive"
}
}Automatic Token Refresh
Universal API automatically refreshes OAuth tokens when they're within 5 minutes of expiration. Your actions and agents always receive valid access tokens.
Summary: Keys Injection by Runtime
| Runtime | How Keys Are Accessed | Example |
|---|---|---|
| Actions (Python) | parameters['keys'] | parameters['keys']['openai']['keyValue'] |
| Agents (Python) | user_keys dict or UAPI_KEYS_JSON env var | user_keys['openai']['keyValue'] |
| MCP Servers (JS) | userContext.keys | userContext.keys.openai.keyValue |