Documentation Index
Fetch the complete documentation index at: https://docs.grantex.dev/llms.txt
Use this file to discover all available pages before exploring further.
Endpoint
POST /v1/vault/credentials
Authentication
Requires a developer API key in the Authorization header.
| Header | Value |
|---|
Authorization | Bearer <api_key> |
Content-Type | application/json |
Request Body
| Field | Type | Required | Description |
|---|
principalId | string | Yes | The principal (end-user) who owns this credential |
service | string | Yes | Service identifier (e.g. "github", "slack", "google"). Use 1-64 characters: letters, numbers, ., _, or -. |
accessToken | string | Yes | The access token to store (encrypted at rest) |
credentialType | string | No | Credential type (default "oauth2") |
refreshToken | string | No | Optional refresh token (encrypted at rest) |
tokenExpiresAt | string | No | ISO-8601 expiry timestamp for the access token |
metadata | object | No | Arbitrary metadata (e.g. scopes, account info) |
Example Request
curl -X POST https://grantex-auth-dd4mtrt2gq-uc.a.run.app/v1/vault/credentials \
-H "Authorization: Bearer gx_..." \
-H "Content-Type: application/json" \
-d '{
"principalId": "user_abc123",
"service": "github",
"accessToken": "ghp_xxxxxxxxxxxx",
"refreshToken": "ghr_xxxxxxxxxxxx",
"tokenExpiresAt": "2026-04-06T12:00:00.000Z",
"metadata": { "scopes": ["repo", "read:org"] }
}'
Response — 201 Created
{
"id": "vc_01HXYZ...",
"principalId": "user_abc123",
"service": "github",
"credentialType": "oauth2",
"createdAt": "2026-04-05T12:00:00.000Z"
}
Response Fields
| Field | Type | Description |
|---|
id | string | Unique vault credential ID |
principalId | string | The principal who owns this credential |
service | string | Service identifier |
credentialType | string | Credential type |
createdAt | string | ISO-8601 creation timestamp |
If a credential already exists for the same (developerId, principalId, service) combination, it will be updated (upsert behavior). The raw access token and refresh token are never returned in any response — they are stored encrypted and only retrievable via the Exchange endpoint.
Error Responses
| Status | Code | Description |
|---|
| 400 | BAD_REQUEST | Missing principalId, service, or accessToken |
| 400 | BAD_REQUEST | Invalid service identifier |
| 401 | UNAUTHORIZED | Invalid or missing API key |
SDK Examples
import Grantex from '@grantex/sdk';
const grantex = new Grantex({ apiKey: 'gx_...' });
const cred = await grantex.vault.store({
principalId: 'user_abc123',
service: 'github',
accessToken: 'ghp_xxxxxxxxxxxx',
refreshToken: 'ghr_xxxxxxxxxxxx',
metadata: { scopes: ['repo', 'read:org'] },
});