Keep the personal half of the desktop in one place, and ask before installing it
Agent instructions, skills, SSH host aliases and expansion triggers are worth having identical on every machine one person owns, and belong in none of the shared configuration. They live in user/ now, with a manifest saying where each piece goes and a link-user stage that puts it there. That stage does nothing unless the machine said yes. Somebody who clones Panama to try the desktop keeps their own ~/.claude/CLAUDE.md exactly where it was; the question names the destinations and defaults to no. Anything displaced goes to config/old rather than being deleted. ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md were byte-identical copies of one file, which is the drift this exists to prevent. Also adds the vitals toggles for the battery and Claude usage readouts, which had preferences and no way to reach them.
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
# Authentication
|
||||
|
||||
Infisical supports multiple authentication methods. Machine identity Universal Auth is the recommended approach for production use.
|
||||
|
||||
## Universal Auth (Recommended)
|
||||
|
||||
Universal Auth is the preferred machine identity authentication method for all use cases.
|
||||
|
||||
### Login Endpoint
|
||||
|
||||
```
|
||||
POST /api/v1/auth/universal-auth/login
|
||||
```
|
||||
|
||||
### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"clientId": "string",
|
||||
"clientSecret": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"expiresIn": 3600,
|
||||
"accessTokenMaxTTL": 86400,
|
||||
"tokenType": "Bearer"
|
||||
}
|
||||
```
|
||||
|
||||
### Example cURL
|
||||
|
||||
```bash
|
||||
curl -X POST https://us.infisical.com/api/v1/auth/universal-auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"clientId": "YOUR_CLIENT_ID",
|
||||
"clientSecret": "YOUR_CLIENT_SECRET"
|
||||
}'
|
||||
```
|
||||
|
||||
### Using the Token
|
||||
|
||||
Include the token in all subsequent requests as a Bearer token:
|
||||
|
||||
```bash
|
||||
curl -X GET https://us.infisical.com/api/v4/secrets?projectId=PROJECT_ID&environment=dev \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Alternative Auth Methods
|
||||
|
||||
Infisical supports additional authentication methods for machine identities:
|
||||
|
||||
### AWS Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/aws-auth/login
|
||||
```
|
||||
|
||||
Login with AWS IAM credentials. Useful for AWS-hosted applications.
|
||||
|
||||
### Azure Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/azure-auth/login
|
||||
```
|
||||
|
||||
Login with Azure managed identity. Ideal for Azure-hosted applications.
|
||||
|
||||
### GCP Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/gcp-auth/login
|
||||
```
|
||||
|
||||
Login with GCP service account. Recommended for Google Cloud deployments.
|
||||
|
||||
### Kubernetes Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/kubernetes-auth/login
|
||||
```
|
||||
|
||||
Login with Kubernetes service account token. Perfect for containerized workloads.
|
||||
|
||||
### OIDC Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/oidc-auth/login
|
||||
```
|
||||
|
||||
Login via OpenID Connect provider. Supports any OIDC-compliant provider.
|
||||
|
||||
### JWT Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/jwt-auth/login
|
||||
```
|
||||
|
||||
Login with custom JWT. Useful for custom authentication systems.
|
||||
|
||||
### LDAP Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/ldap-auth/login
|
||||
```
|
||||
|
||||
Login with LDAP credentials. Enterprise directory integration.
|
||||
|
||||
## Token Refresh
|
||||
|
||||
Access tokens expire after the `expiresIn` seconds returned in the login response. For long-lived integrations, implement token refresh logic:
|
||||
|
||||
```javascript
|
||||
// Pseudocode for token refresh
|
||||
let tokenExpiresAt = Date.now() + (expiresIn * 1000);
|
||||
|
||||
async function getValidToken() {
|
||||
if (Date.now() >= tokenExpiresAt - 60000) {
|
||||
// Refresh within 1 minute of expiry
|
||||
const response = await login(clientId, clientSecret);
|
||||
token = response.accessToken;
|
||||
tokenExpiresAt = Date.now() + (response.expiresIn * 1000);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
```
|
||||
|
||||
The `accessTokenMaxTTL` value indicates the maximum lifetime of the token from issuance (typically 24 hours), which may be shorter than the server's token validity window.
|
||||
|
||||
## Deprecated: Service Tokens
|
||||
|
||||
Service tokens (prefixed with `st.`) are deprecated and should not be used in new code. They lack:
|
||||
- Fine-grained permission controls
|
||||
- Machine identity features
|
||||
- Audit logging capabilities
|
||||
- Rotation enforcement
|
||||
|
||||
Migrate all service token usage to machine identities with Universal Auth.
|
||||
|
||||
## Region Selection
|
||||
|
||||
Choose the appropriate Infisical region endpoint:
|
||||
|
||||
- **US Region**: `https://us.infisical.com`
|
||||
- **EU Region**: `https://eu.infisical.com`
|
||||
- **Self-Hosted**: Use your custom domain (e.g., `https://secrets.mycompany.com`)
|
||||
|
||||
## Headers
|
||||
|
||||
All authentication requests must include:
|
||||
|
||||
```
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### 401 Unauthorized
|
||||
|
||||
- Verify clientId and clientSecret are correct
|
||||
- Confirm the token hasn't expired
|
||||
- Check that the Bearer token is included in the Authorization header
|
||||
|
||||
### 403 Forbidden
|
||||
|
||||
- Machine identity may not have permission for the requested resource
|
||||
- Verify identity auth method is configured for the project
|
||||
- Check role-based access controls (RBAC) in the project
|
||||
|
||||
### 404 Not Found
|
||||
|
||||
- Confirm you're using the correct endpoint URL
|
||||
- Verify the projectId exists and is accessible
|
||||
- Check that the region (us.infisical.com vs eu.infisical.com) matches your deployment
|
||||
@@ -0,0 +1,287 @@
|
||||
# Pagination and Rate Limits
|
||||
|
||||
## Pagination
|
||||
|
||||
Infisical uses offset-based pagination for list endpoints. All responses include pagination metadata.
|
||||
|
||||
### Pagination Parameters
|
||||
|
||||
| Parameter | Type | Default | Max | Description |
|
||||
|-----------|------|---------|-----|-------------|
|
||||
| offset | integer | 0 | - | Number of items to skip from the beginning |
|
||||
| limit | integer | 20 | 100 | Maximum number of items to return in this request |
|
||||
|
||||
### Pagination Response
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [...],
|
||||
"total": 150,
|
||||
"offset": 0,
|
||||
"limit": 20
|
||||
}
|
||||
```
|
||||
|
||||
- **total**: Total count of all available items (ignoring pagination)
|
||||
- **offset**: Requested offset
|
||||
- **limit**: Requested limit (may be less if fewer items available)
|
||||
- **items**: Array of results for this page
|
||||
|
||||
### Example: Paginating Through All Results
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Retrieve all secrets in batches of 20
|
||||
offset=0
|
||||
limit=20
|
||||
total=-1
|
||||
|
||||
while [ $offset -lt $total ] || [ $total -eq -1 ]; do
|
||||
response=$(curl -s "https://us.infisical.com/api/v4/secrets?projectId=abc123&environment=dev&offset=$offset&limit=$limit" \
|
||||
-H "Authorization: Bearer TOKEN")
|
||||
|
||||
# Extract items and total from response
|
||||
total=$(echo $response | jq '.total')
|
||||
items=$(echo $response | jq '.secrets[]')
|
||||
|
||||
# Process items
|
||||
echo "Processing items $offset to $((offset + limit))..."
|
||||
|
||||
offset=$((offset + limit))
|
||||
done
|
||||
```
|
||||
|
||||
### Pagination Best Practices
|
||||
|
||||
1. **Start with offset=0**: Always begin pagination at offset 0
|
||||
2. **Use maximum limit**: Set `limit=100` for faster retrieval (unless you need fewer items)
|
||||
3. **Check total**: Use the `total` value to determine if more pages exist: `hasMore = (offset + limit) < total`
|
||||
4. **Handle edge cases**: Always check if `limit` in response is less than requested (indicates fewer items available)
|
||||
5. **Respect rate limits**: Add delays between requests if hitting rate limits
|
||||
|
||||
## Rate Limits (Cloud Only)
|
||||
|
||||
Infisical Cloud deployments have rate limits. Self-hosted deployments have no rate limits.
|
||||
|
||||
### Rate Limit Types
|
||||
|
||||
#### Read Operations (GET, LIST)
|
||||
|
||||
- **Free Tier**: 200 reads per minute
|
||||
- **Pro Tier**: 350 reads per minute
|
||||
- **Enterprise**: Custom limits
|
||||
|
||||
#### Write Operations (CREATE, UPDATE, DELETE)
|
||||
|
||||
- **Free Tier**: 90 writes per minute
|
||||
- **Pro Tier**: 200 writes per minute
|
||||
- **Enterprise**: Custom limits
|
||||
|
||||
#### Secret Operations (All /api/v4/secrets/* endpoints)
|
||||
|
||||
- **Free Tier**: 120 secret ops per minute
|
||||
- **Pro Tier**: 300 secret ops per minute
|
||||
- **Enterprise**: Custom limits
|
||||
|
||||
### Rate Limit Response Headers
|
||||
|
||||
When you hit a rate limit, the API returns HTTP 429 (Too Many Requests):
|
||||
|
||||
```
|
||||
HTTP/1.1 429 Too Many Requests
|
||||
X-RateLimit-Limit: 200
|
||||
X-RateLimit-Remaining: 0
|
||||
X-RateLimit-Reset: 1713350400
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"statusCode": 429,
|
||||
"message": "Too many requests, please try again later."
|
||||
}
|
||||
```
|
||||
|
||||
- **X-RateLimit-Limit**: Maximum requests allowed in the window
|
||||
- **X-RateLimit-Remaining**: Requests remaining in the current window
|
||||
- **X-RateLimit-Reset**: Unix timestamp when the limit resets
|
||||
|
||||
### Handling Rate Limits
|
||||
|
||||
#### Implement Exponential Backoff
|
||||
|
||||
```javascript
|
||||
async function makeRequestWithRetry(url, options, maxRetries = 3) {
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (response.status === 429) {
|
||||
const resetTime = parseInt(response.headers.get('X-RateLimit-Reset')) * 1000;
|
||||
const delayMs = Math.max(resetTime - Date.now(), 1000 * Math.pow(2, attempt - 1));
|
||||
|
||||
console.log(`Rate limited. Waiting ${delayMs}ms before retry...`);
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
throw new Error('Max retries exceeded');
|
||||
}
|
||||
```
|
||||
|
||||
#### Monitor Rate Limit Usage
|
||||
|
||||
```bash
|
||||
curl -s 'https://us.infisical.com/api/v4/secrets?projectId=abc123&environment=dev&limit=1' \
|
||||
-H "Authorization: Bearer TOKEN" \
|
||||
-w "\nRate Limit Remaining: %{http_header{X-RateLimit-Remaining}}\n"
|
||||
```
|
||||
|
||||
#### Batch Operations
|
||||
|
||||
Group multiple operations to reduce request count:
|
||||
|
||||
```bash
|
||||
# Instead of 100 DELETE requests, use one batch delete
|
||||
curl -X DELETE 'https://us.infisical.com/api/v4/secrets/batch' \
|
||||
-H "Authorization: Bearer TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"projectId": "abc123",
|
||||
"environment": "dev",
|
||||
"secretPath": "/",
|
||||
"secretIds": ["id1", "id2", "id3", ...]
|
||||
}'
|
||||
```
|
||||
|
||||
#### Request Queuing
|
||||
|
||||
Implement a request queue to spread requests over time:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import aiohttp
|
||||
from collections import deque
|
||||
|
||||
class RateLimitedClient:
|
||||
def __init__(self, requests_per_minute=200):
|
||||
self.requests_per_minute = requests_per_minute
|
||||
self.min_interval = 60 / requests_per_minute
|
||||
self.last_request_time = 0
|
||||
self.queue = deque()
|
||||
|
||||
async def request(self, session, method, url, **kwargs):
|
||||
# Wait if necessary to maintain rate limit
|
||||
elapsed = asyncio.get_event_loop().time() - self.last_request_time
|
||||
if elapsed < self.min_interval:
|
||||
await asyncio.sleep(self.min_interval - elapsed)
|
||||
|
||||
async with session.request(method, url, **kwargs) as response:
|
||||
self.last_request_time = asyncio.get_event_loop().time()
|
||||
return await response.json()
|
||||
```
|
||||
|
||||
## Required Headers
|
||||
|
||||
All API requests must include:
|
||||
|
||||
```
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer YOUR_ACCESS_TOKEN
|
||||
```
|
||||
|
||||
### Example: Complete Request with Headers
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v4/secrets?projectId=abc123&environment=dev&offset=0&limit=20' \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc..."
|
||||
```
|
||||
|
||||
## HTTP Status Codes
|
||||
|
||||
| Code | Meaning | When It Occurs |
|
||||
|------|---------|----------------|
|
||||
| 200 | OK | Successful GET, PATCH, DELETE |
|
||||
| 201 | Created | Successful POST |
|
||||
| 400 | Bad Request | Invalid parameters or request body |
|
||||
| 401 | Unauthorized | Missing or invalid token |
|
||||
| 403 | Forbidden | Insufficient permissions |
|
||||
| 404 | Not Found | Resource doesn't exist |
|
||||
| 409 | Conflict | Duplicate secret name or resource conflict |
|
||||
| 429 | Too Many Requests | Rate limit exceeded (cloud only) |
|
||||
| 500 | Internal Error | Server error |
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Use pagination**: Limit each request to 100 items maximum
|
||||
2. **Cache responses**: Store secret values locally to reduce API calls
|
||||
3. **Use appropriate timeouts**: Set 30-second timeouts for API calls
|
||||
4. **Batch operations**: Combine multiple operations into single requests where possible
|
||||
5. **Monitor headers**: Check X-RateLimit-Remaining to anticipate throttling
|
||||
6. **Implement exponential backoff**: Automatically retry failed requests with increasing delays
|
||||
7. **Use webhooks**: Subscribe to changes instead of polling for updates (if available)
|
||||
|
||||
## Example: Comprehensive Pagination with Error Handling
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
PROJECT_ID="abc123"
|
||||
ENVIRONMENT="dev"
|
||||
API_BASE="https://us.infisical.com"
|
||||
TOKEN="your_access_token"
|
||||
BATCH_SIZE=100
|
||||
|
||||
offset=0
|
||||
total_processed=0
|
||||
|
||||
while true; do
|
||||
# Make request with error handling
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
"$API_BASE/api/v4/secrets?projectId=$PROJECT_ID&environment=$ENVIRONMENT&offset=$offset&limit=$BATCH_SIZE" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
# Extract body and status code
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | head -n-1)
|
||||
|
||||
# Check for errors
|
||||
if [ "$http_code" = "429" ]; then
|
||||
reset_time=$(curl -s -I "$API_BASE/api/v4/secrets?projectId=$PROJECT_ID&environment=$ENVIRONMENT" \
|
||||
-H "Authorization: Bearer $TOKEN" | grep X-RateLimit-Reset | awk '{print $2}')
|
||||
echo "Rate limited. Waiting until $reset_time..."
|
||||
sleep 60
|
||||
continue
|
||||
elif [ "$http_code" != "200" ]; then
|
||||
echo "Error: HTTP $http_code"
|
||||
echo "$body" | jq .
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Process response
|
||||
total=$(echo "$body" | jq '.total')
|
||||
count=$(echo "$body" | jq '.secrets | length')
|
||||
|
||||
echo "Processing items $offset-$((offset + count)) of $total..."
|
||||
|
||||
# Do something with the secrets
|
||||
echo "$body" | jq '.secrets[] | .secretName'
|
||||
|
||||
total_processed=$((total_processed + count))
|
||||
|
||||
# Check if we've retrieved all items
|
||||
if [ $total_processed -ge $total ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
offset=$((offset + BATCH_SIZE))
|
||||
done
|
||||
|
||||
echo "Processed $total_processed items total"
|
||||
```
|
||||
@@ -0,0 +1,496 @@
|
||||
# Projects and Identities
|
||||
|
||||
## Projects
|
||||
|
||||
Projects are containers for secrets, environments, and team members. Always use `/api/v1/projects` (not the deprecated `/api/v1/workspace`).
|
||||
|
||||
### List Projects
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/projects
|
||||
```
|
||||
|
||||
#### Query Parameters
|
||||
|
||||
| Parameter | Type | Default | Max | Description |
|
||||
|-----------|------|---------|-----|-------------|
|
||||
| offset | integer | 0 | - | Number of items to skip |
|
||||
| limit | integer | 20 | 100 | Number of items to return |
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"projects": [
|
||||
{
|
||||
"id": "project-id-uuid",
|
||||
"name": "My Project",
|
||||
"slug": "my-project",
|
||||
"createdAt": "2026-04-01T10:00:00.000Z",
|
||||
"updatedAt": "2026-04-16T10:30:00.000Z",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"total": 5
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v1/projects?offset=0&limit=20' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
### Get Project
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/projects/{projectId}
|
||||
```
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"project": {
|
||||
"id": "project-id-uuid",
|
||||
"name": "My Project",
|
||||
"slug": "my-project",
|
||||
"createdAt": "2026-04-01T10:00:00.000Z",
|
||||
"updatedAt": "2026-04-16T10:30:00.000Z",
|
||||
"version": 1,
|
||||
"environments": [
|
||||
{
|
||||
"id": "env-id",
|
||||
"name": "Development",
|
||||
"slug": "dev",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "env-id-2",
|
||||
"name": "Production",
|
||||
"slug": "prod",
|
||||
"version": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v1/projects/abc123' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
### Create Project
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
POST /api/v1/projects
|
||||
```
|
||||
|
||||
#### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"slug": "string (optional)"
|
||||
}
|
||||
```
|
||||
|
||||
#### Response
|
||||
|
||||
Returns the created project object.
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X POST 'https://us.infisical.com/api/v1/projects' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "New Project",
|
||||
"slug": "new-project"
|
||||
}'
|
||||
```
|
||||
|
||||
### Update Project
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
PATCH /api/v1/projects/{projectId}
|
||||
```
|
||||
|
||||
#### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string (optional)",
|
||||
"slug": "string (optional)"
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X PATCH 'https://us.infisical.com/api/v1/projects/abc123' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Updated Project Name"
|
||||
}'
|
||||
```
|
||||
|
||||
### Delete Project
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
DELETE /api/v1/projects/{projectId}
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X DELETE 'https://us.infisical.com/api/v1/projects/abc123' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Environments
|
||||
|
||||
Environments (dev, staging, prod) organize secrets by deployment target.
|
||||
|
||||
### List Project Environments
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/projects/{projectId}/environments
|
||||
```
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"environments": [
|
||||
{
|
||||
"id": "env-id-uuid",
|
||||
"name": "Development",
|
||||
"slug": "dev",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "env-id-2",
|
||||
"name": "Production",
|
||||
"slug": "prod",
|
||||
"version": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v1/projects/abc123/environments' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Project Members
|
||||
|
||||
Manage who has access to a project and their role.
|
||||
|
||||
### List Project Members
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/projects/{projectId}/memberships
|
||||
```
|
||||
|
||||
#### Query Parameters
|
||||
|
||||
| Parameter | Type | Default | Max |
|
||||
|-----------|------|---------|-----|
|
||||
| offset | integer | 0 | - |
|
||||
| limit | integer | 20 | 100 |
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"memberships": [
|
||||
{
|
||||
"id": "membership-id",
|
||||
"projectId": "project-id",
|
||||
"userId": "user-id",
|
||||
"user": {
|
||||
"id": "user-id",
|
||||
"email": "[email protected]"
|
||||
},
|
||||
"role": "admin"
|
||||
}
|
||||
],
|
||||
"total": 3
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v1/projects/abc123/memberships' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Machine Identities
|
||||
|
||||
Machine identities allow non-human accounts to authenticate and access secrets.
|
||||
|
||||
### List Identities
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/identities
|
||||
```
|
||||
|
||||
#### Query Parameters
|
||||
|
||||
| Parameter | Type | Default | Max | Description |
|
||||
|-----------|------|---------|-----|-------------|
|
||||
| offset | integer | 0 | - | Number to skip |
|
||||
| limit | integer | 20 | 100 | Number to return |
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"identities": [
|
||||
{
|
||||
"id": "identity-id-uuid",
|
||||
"name": "Production API",
|
||||
"createdAt": "2026-04-01T10:00:00.000Z",
|
||||
"updatedAt": "2026-04-16T10:30:00.000Z"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v1/identities?offset=0&limit=20' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
### Get Identity
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/identities/{identityId}
|
||||
```
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"identity": {
|
||||
"id": "identity-id-uuid",
|
||||
"name": "Production API",
|
||||
"universalAuthClientId": "machine-identity-uuid",
|
||||
"createdAt": "2026-04-01T10:00:00.000Z",
|
||||
"updatedAt": "2026-04-16T10:30:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Create Identity
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
POST /api/v1/identities
|
||||
```
|
||||
|
||||
#### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Update Identity
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
PATCH /api/v1/identities/{identityId}
|
||||
```
|
||||
|
||||
#### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string (optional)"
|
||||
}
|
||||
```
|
||||
|
||||
### Delete Identity
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
DELETE /api/v1/identities/{identityId}
|
||||
```
|
||||
|
||||
## Identity Auth Methods
|
||||
|
||||
Configure how machine identities authenticate.
|
||||
|
||||
### Universal Auth (Recommended)
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/auth/universal-auth/identities/{identityId}
|
||||
POST /api/v1/auth/universal-auth/identities/{identityId}
|
||||
DELETE /api/v1/auth/universal-auth/identities/{identityId}
|
||||
```
|
||||
|
||||
#### Example: Get Universal Auth Config
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v1/auth/universal-auth/identities/identity-id' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
Response includes `clientId` and regenerated `clientSecret`.
|
||||
|
||||
#### AWS Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/aws-auth/identities/{identityId}
|
||||
PATCH /api/v1/auth/aws-auth/identities/{identityId}
|
||||
```
|
||||
|
||||
#### Azure Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/azure-auth/identities/{identityId}
|
||||
PATCH /api/v1/auth/azure-auth/identities/{identityId}
|
||||
```
|
||||
|
||||
#### GCP Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/gcp-auth/identities/{identityId}
|
||||
PATCH /api/v1/auth/gcp-auth/identities/{identityId}
|
||||
```
|
||||
|
||||
#### Kubernetes Auth
|
||||
|
||||
```
|
||||
POST /api/v1/auth/kubernetes-auth/identities/{identityId}
|
||||
PATCH /api/v1/auth/kubernetes-auth/identities/{identityId}
|
||||
```
|
||||
|
||||
## Groups
|
||||
|
||||
Organize machine identities and manage permissions at scale.
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v1/groups
|
||||
POST /api/v1/groups
|
||||
GET /api/v1/groups/{groupId}
|
||||
PATCH /api/v1/groups/{groupId}
|
||||
DELETE /api/v1/groups/{groupId}
|
||||
```
|
||||
|
||||
### Example: List Groups
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v1/groups' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Folders
|
||||
|
||||
Organize secrets into hierarchical folder structures.
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v2/folders
|
||||
POST /api/v2/folders
|
||||
PATCH /api/v2/folders/{folderId}
|
||||
DELETE /api/v2/folders/{folderId}
|
||||
```
|
||||
|
||||
### List Folders
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v2/folders?projectId=abc123&environment=dev' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Secret Imports
|
||||
|
||||
Import secrets from one environment into another.
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v2/secret-imports
|
||||
POST /api/v2/secret-imports
|
||||
PATCH /api/v2/secret-imports/{importId}
|
||||
DELETE /api/v2/secret-imports/{importId}
|
||||
```
|
||||
|
||||
### Example: List Secret Imports
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v2/secret-imports?projectId=abc123&environment=dev' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Deprecated Endpoints
|
||||
|
||||
**Do not use these endpoints in new code:**
|
||||
|
||||
- `/api/v1/workspace/*` — Use `/api/v1/projects` instead
|
||||
- Service token endpoints — Use machine identities with Universal Auth instead
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Set Up a New Machine Identity
|
||||
|
||||
1. Create identity: `POST /api/v1/identities` → get `identityId`
|
||||
2. Configure auth: `POST /api/v1/auth/universal-auth/identities/{identityId}`
|
||||
3. Login: `POST /api/v1/auth/universal-auth/login` with `clientId` and `clientSecret`
|
||||
4. Use returned `accessToken` for all subsequent API calls
|
||||
|
||||
### Add Identity to Project
|
||||
|
||||
1. Create identity and auth method (see above)
|
||||
2. Create a folder/path in the target project
|
||||
3. Create project membership or use RBAC rules to grant access
|
||||
4. Test login with the new credentials
|
||||
|
||||
### Organize Secrets with Folders
|
||||
|
||||
1. Create folder: `POST /api/v2/folders` with `projectId`, `environment`, `folderName`
|
||||
2. Create secrets under folder: `POST /api/v4/secrets/SECRET_NAME` with `secretPath: "/folder-name"`
|
||||
3. List secrets in folder: `GET /api/v4/secrets?secretPath=/folder-name`
|
||||
@@ -0,0 +1,338 @@
|
||||
# Secrets Endpoints
|
||||
|
||||
All secret operations use `/api/v4/secrets`. Previous API versions (v1, v2, v3) are deprecated.
|
||||
|
||||
## List Secrets
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v4/secrets
|
||||
```
|
||||
|
||||
### Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Max | Description |
|
||||
|-----------|------|----------|---------|-----|-------------|
|
||||
| projectId | string | Yes | - | - | ID of the project |
|
||||
| environment | string | Yes | - | - | Environment slug (e.g., "dev", "prod") |
|
||||
| secretPath | string | No | "/" | - | Secret folder path (e.g., "/database", "/") |
|
||||
| offset | integer | No | 0 | - | Number of items to skip for pagination |
|
||||
| limit | integer | No | 20 | 100 | Number of items to return per page |
|
||||
| viewSecretValue | boolean | No | false | - | Include plaintext secret values in response |
|
||||
| expandSecretReferences | boolean | No | false | - | Expand secret references (e.g., `${OTHER_SECRET}`) |
|
||||
| recursive | boolean | No | false | - | Include secrets from all subdirectories |
|
||||
| includeImports | boolean | No | false | - | Include secrets from imported secret environments |
|
||||
| tagSlugs | string | No | - | - | Comma-separated tag slugs to filter by |
|
||||
| metadataFilter | string | No | - | - | JSON filter for metadata-based search |
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"secrets": [
|
||||
{
|
||||
"id": "secret-id-uuid",
|
||||
"version": 1,
|
||||
"workspace": "workspace-id",
|
||||
"project": "project-id",
|
||||
"environment": "dev",
|
||||
"secretPath": "/",
|
||||
"secretName": "DATABASE_URL",
|
||||
"secretValue": "postgres://user:pass@localhost/db",
|
||||
"secretComment": "Production database connection",
|
||||
"type": "shared",
|
||||
"tags": [
|
||||
{
|
||||
"id": "tag-id",
|
||||
"slug": "database",
|
||||
"name": "Database",
|
||||
"color": "#3b82f6"
|
||||
}
|
||||
],
|
||||
"createdAt": "2026-04-16T10:30:00.000Z",
|
||||
"updatedAt": "2026-04-16T10:30:00.000Z",
|
||||
"createdBy": "user-id"
|
||||
}
|
||||
],
|
||||
"total": 42,
|
||||
"offset": 0,
|
||||
"limit": 20
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v4/secrets?projectId=abc123&environment=dev&offset=0&limit=20&viewSecretValue=true' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Get Secret
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
GET /api/v4/secrets/{secretName}
|
||||
```
|
||||
|
||||
### Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| projectId | string | Yes | - | ID of the project |
|
||||
| environment | string | Yes | - | Environment slug |
|
||||
| secretPath | string | No | "/" | Secret folder path |
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"secret": {
|
||||
"id": "secret-id-uuid",
|
||||
"version": 1,
|
||||
"workspace": "workspace-id",
|
||||
"project": "project-id",
|
||||
"environment": "dev",
|
||||
"secretPath": "/",
|
||||
"secretName": "API_KEY",
|
||||
"secretValue": "sk_live_abc123def456ghi789",
|
||||
"secretComment": "Third-party API key",
|
||||
"type": "shared",
|
||||
"tags": [],
|
||||
"createdAt": "2026-04-16T10:30:00.000Z",
|
||||
"updatedAt": "2026-04-16T10:30:00.000Z",
|
||||
"createdBy": "user-id"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://us.infisical.com/api/v4/secrets/API_KEY?projectId=abc123&environment=dev&secretPath=/' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Create Secret
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
POST /api/v4/secrets/{secretName}
|
||||
```
|
||||
|
||||
### Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| projectId | string | Yes | ID of the project |
|
||||
| environment | string | Yes | Environment slug |
|
||||
| secretPath | string | No | Secret folder path (default: "/") |
|
||||
| secretValue | string | Yes | The secret value (plaintext) |
|
||||
| type | string | No | "shared" or "personal" (default: "shared") |
|
||||
| tagIds | array | No | List of tag IDs to attach |
|
||||
| secretComment | string | No | Comment/description for the secret |
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"secret": {
|
||||
"id": "secret-id-uuid",
|
||||
"version": 1,
|
||||
"workspace": "workspace-id",
|
||||
"project": "project-id",
|
||||
"environment": "dev",
|
||||
"secretPath": "/",
|
||||
"secretName": "NEW_SECRET",
|
||||
"secretValue": "super-secret-value",
|
||||
"secretComment": "My new secret",
|
||||
"type": "shared",
|
||||
"tags": [],
|
||||
"createdAt": "2026-04-16T10:30:00.000Z",
|
||||
"updatedAt": "2026-04-16T10:30:00.000Z",
|
||||
"createdBy": "user-id"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl -X POST 'https://us.infisical.com/api/v4/secrets/DATABASE_PASSWORD' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"projectId": "abc123",
|
||||
"environment": "dev",
|
||||
"secretPath": "/",
|
||||
"secretValue": "my-secure-password",
|
||||
"type": "shared",
|
||||
"secretComment": "Database password for dev environment"
|
||||
}'
|
||||
```
|
||||
|
||||
## Update Secret
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
PATCH /api/v4/secrets/{secretName}
|
||||
```
|
||||
|
||||
### Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| projectId | string | Yes | ID of the project |
|
||||
| environment | string | Yes | Environment slug |
|
||||
| secretPath | string | No | Secret folder path |
|
||||
| secretValue | string | No | New secret value |
|
||||
| secretComment | string | No | Updated comment/description |
|
||||
| tagIds | array | No | Updated list of tag IDs |
|
||||
|
||||
### Response
|
||||
|
||||
Same as Create Secret response.
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl -X PATCH 'https://us.infisical.com/api/v4/secrets/DATABASE_PASSWORD' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"projectId": "abc123",
|
||||
"environment": "dev",
|
||||
"secretPath": "/",
|
||||
"secretValue": "new-secure-password"
|
||||
}'
|
||||
```
|
||||
|
||||
## Delete Secret
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
DELETE /api/v4/secrets/{secretName}
|
||||
```
|
||||
|
||||
### Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| projectId | string | Yes | ID of the project |
|
||||
| environment | string | Yes | Environment slug |
|
||||
| secretPath | string | No | Secret folder path (default: "/") |
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"secret": {
|
||||
"id": "secret-id-uuid",
|
||||
"secretName": "DELETED_SECRET"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl -X DELETE 'https://us.infisical.com/api/v4/secrets/OLD_SECRET?projectId=abc123&environment=dev&secretPath=/' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
## Batch Delete Secrets
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
DELETE /api/v4/secrets/batch
|
||||
```
|
||||
|
||||
### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"projectId": "string",
|
||||
"environment": "string",
|
||||
"secretPath": "string",
|
||||
"secretIds": ["uuid1", "uuid2", "uuid3"]
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"deletedSecrets": [
|
||||
{
|
||||
"id": "uuid1",
|
||||
"secretName": "SECRET_1"
|
||||
},
|
||||
{
|
||||
"id": "uuid2",
|
||||
"secretName": "SECRET_2"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```bash
|
||||
curl -X DELETE 'https://us.infisical.com/api/v4/secrets/batch' \
|
||||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"projectId": "abc123",
|
||||
"environment": "dev",
|
||||
"secretPath": "/",
|
||||
"secretIds": ["id1-uuid", "id2-uuid"]
|
||||
}'
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
### API Version
|
||||
|
||||
- Use `/api/v4/secrets` for all new code
|
||||
- `/api/v1/secrets`, `/api/v2/secrets`, and `/api/v3/secrets` are deprecated
|
||||
- Migrate existing integrations to v4 endpoints
|
||||
|
||||
### Secret Names
|
||||
|
||||
- Must be unique within the environment and secret path
|
||||
- Use uppercase with underscores (e.g., `DATABASE_PASSWORD`)
|
||||
- Cannot contain spaces or special characters
|
||||
|
||||
### Secret Types
|
||||
|
||||
- **shared**: Visible to all project members with appropriate permissions
|
||||
- **personal**: Only visible to the user who created it
|
||||
|
||||
### Secret Values
|
||||
|
||||
- Plaintext strings only
|
||||
- For large values, base64-encode before creating
|
||||
- References using `${SECRET_NAME}` syntax are supported when `expandSecretReferences=true`
|
||||
|
||||
### Tags
|
||||
|
||||
- Secrets can have multiple tags
|
||||
- Tags are organization-wide but applied per secret
|
||||
- Use `tagSlugs` parameter to filter list results by tag
|
||||
|
||||
### Pagination
|
||||
|
||||
- Always specify `offset` and `limit` for predictable results
|
||||
- Default limit is 20; maximum is 100
|
||||
- Use `total` to determine remaining items: `hasMore = (offset + limit) < total`
|
||||
|
||||
### Performance
|
||||
|
||||
- For listing many secrets (>1000), use pagination with `limit=100`
|
||||
- Avoid `viewSecretValue=true` on large lists unless values are needed
|
||||
- Use `recursive=false` by default for better performance
|
||||
Reference in New Issue
Block a user