Authentication
Manage API keys and verify identity.
All auth endpoints support session authentication (browser cookie) with API key fallback. This means you can call these endpoints from the browser (using your Meteor login session) or from scripts and external clients (using a valid API key in the X-API-Key header).
POST /api/v1/me/api-keys
Create a new API key
Returns the raw key value once -- store it securely.
Authentication: Session (browser cookie) or API key
Request Body:
{
"name": "My CI/CD Key",
"scopes": ["apps:read", "apps:deploy", "workflows:execute"],
"expiresInDays": 90
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable key name (non-empty) |
scopes | string[] | Yes | Permission scopes (non-empty array; see Scopes) |
expiresInDays | integer | No | Days until expiration. Omit for no expiration |
Response: 201 Created
{
"data": {
"id": "67a1b2c3d4e5f6a7b8c9d0e1",
"key": "sk-prod-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"name": "My CI/CD Key",
"keyPrefix": "sk-prod-a1b2",
"scopes": ["apps:read", "apps:deploy", "workflows:execute"],
"expiresAt": "2025-05-07T00:00:00.000Z",
"createdAt": "2025-02-07T00:00:00.000Z"
},
"meta": { "requestId": "req_abc123" }
}
| Field | Type | Description |
|---|---|---|
id | string | MongoDB document ID |
key | string | The raw API key (only returned once) |
name | string | Key name |
keyPrefix | string | First 12 characters of the key |
scopes | string[] | Assigned permission scopes |
expiresAt | string | null | ISO-8601 expiration date, or null if no expiration |
createdAt | string | ISO-8601 creation date |
The key field is only returned once at creation time. Store it securely -- it cannot be retrieved later.
GET /api/v1/me/api-keys
List API keys for the current user
Authentication: Session (browser cookie) or API key
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | string | No | Filter by status: active, revoked, expired |
limit | query | integer | No | Max results (default: 50, max: 200) |
cursor | query | string | No | meta.nextCursor of the previous page; omit for the first page |
sort | query | string | No | Sort field (default: -createdAt) |
Response: 200 OK (paginated)
{
"data": [
{
"_id": "67a1b2c3d4e5f6a7b8c9d0e1",
"keyPrefix": "sk-prod-a1b2",
"name": "My CI/CD Key",
"userId": "user123",
"organizationId": "org-abc",
"scopes": ["apps:read", "apps:deploy"],
"status": "active",
"expiresAt": "2025-05-07T00:00:00.000Z",
"lastUsedAt": "2025-02-06T10:30:00.000Z",
"lastUsedIp": "192.168.1.1",
"createdAt": "2025-02-07T00:00:00.000Z",
"revokedAt": null,
"revokedBy": null,
"metadata": null
}
],
"meta": { "total": 3, "limit": 50, "nextCursor": null, "requestId": "req_abc123" }
}
| Field | Type | Description |
|---|---|---|
_id | string | MongoDB document ID |
keyPrefix | string | First 12 characters of the key |
name | string | Key name |
userId | string | Owning user ID |
organizationId | string | null | Bound organization |
scopes | string[] | Permission scopes |
status | string | active, revoked, or expired |
expiresAt | string | null | Expiration date |
lastUsedAt | string | null | Last request timestamp |
lastUsedIp | string | null | Last request IP address |
createdAt | string | Creation timestamp |
revokedAt | string | null | Revocation timestamp (if revoked) |
revokedBy | string | null | User who revoked (if revoked) |
metadata | object | null | Optional metadata (userAgent, description) |
GET /api/v1/me/api-keys/:id
Get a single API key
Authentication: Session (browser cookie) or API key
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | API key ID (_id from list response) |
Response: 200 OK
{
"data": {
"_id": "67a1b2c3d4e5f6a7b8c9d0e1",
"keyPrefix": "sk-prod-a1b2",
"name": "My CI/CD Key",
"userId": "user123",
"organizationId": "org-abc",
"scopes": ["apps:read", "apps:deploy"],
"status": "active",
"expiresAt": "2025-05-07T00:00:00.000Z",
"lastUsedAt": "2025-02-06T10:30:00.000Z",
"lastUsedIp": "192.168.1.1",
"createdAt": "2025-02-07T00:00:00.000Z",
"revokedAt": null,
"revokedBy": null,
"metadata": null
},
"meta": { "requestId": "req_abc123" }
}
Returns the same fields as the list endpoint for a single key.
DELETE /api/v1/me/api-keys/:id
Revoke an API key
Permanently revokes the key. This cannot be undone. Default Platform Keys cannot be revoked -- use rotate instead.
Authentication: Session (browser cookie) or API key
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | API key ID |
Response: 204 No Content
POST /api/v1/me/api-keys/:id/rotate
Rotate an API key
Revokes the old key and creates a new one with the same name, scopes, and expiration. For Default Platform Keys, also updates profile.stronglyApiKey on the user document.
Authentication: Session (browser cookie) or API key
Parameters:
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | API key ID |
Response: 201 Created
{
"data": {
"id": "67b2c3d4e5f6a7b8c9d0e1f2",
"key": "sk-prod-q1w2e3r4t5y6u7i8o9p0a1s2d3f4g5h6",
"name": "My CI/CD Key",
"keyPrefix": "sk-prod-q1w2",
"scopes": ["apps:read", "apps:deploy"],
"expiresAt": "2025-05-07T00:00:00.000Z",
"createdAt": "2025-02-08T00:00:00.000Z"
},
"meta": { "requestId": "req_abc123" }
}
Returns the same fields as the create endpoint, including the new raw key.
The new key is only returned once. Store it securely -- the old key is immediately revoked and cannot be used.
GET /api/v1/me
Who you are authenticated as
Your user, your organization, and the API key the call used. Documented with your account under Users; it needs no scope, so it is the simplest way to check a key works.
Troubleshooting 401 Errors
If you receive a 401 Unauthorized response when using an API key, check the following:
1. Verify the header format
The key must be sent in the X-API-Key header:
curl -H "X-API-Key: sk-prod-your-key-here" \
https://<your-instance>/api/v1/me
2. Verify the key prefix
All API keys start with sk-prod-. If your key does not start with this prefix, it is not a valid Strongly API key.
3. Check key status
Your key may have been revoked or expired. List your keys via the UI (Profile > Security > API Keys) or via session auth:
# List keys using session auth (from browser dev tools, copy your meteor_login_token cookie)
curl -b "meteor_login_token=your-session-token" \
https://<your-instance>/api/v1/me/api-keys?status=active
4. Confirm there are no extra characters
Ensure no whitespace, newlines, or quotes are included in the key value. Copy-paste errors are common.
5. Test with GET /me
GET /api/v1/me is the simplest way to verify your key works:
curl -v -H "X-API-Key: sk-prod-your-key-here" \
https://<your-instance>/api/v1/me
A successful response returns you, your organization and the key's details. A 401 response means the key is invalid, expired, or revoked.
Default Platform Key
When a new user is created, a Default Platform Key is automatically provisioned with * (wildcard) scopes. This key is:
- Stored in
profile.stronglyApiKeyon the user document for workspace injection - Marked as the default platform key in the API Keys list in the UI (Profile > Security > API Keys); the REST key list and get do not return that flag
- Cannot be revoked -- use rotate instead to replace it
- Automatically rotated when you rotate it via the API or UI, keeping
profile.stronglyApiKeyin sync
Workspaces use this key as their STRONGLY_API_KEY environment variable, so rotating it will require restarting running workspaces to pick up the new key.