> ## 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.

# Store Vault Credential

> Store an encrypted service credential in the Grantex Vault for a principal.

## Endpoint

```
POST /v1/vault/credentials
```

## Authentication

Requires a developer API key in the `Authorization` header.

## Request Headers

| 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

```bash theme={null}
curl -X POST https://api.grantex.dev/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

```json theme={null}
{
  "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 |

<Note>
  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](/api-reference/vault/exchange) endpoint.
</Note>

## 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

<CodeGroup>
  ```typescript TypeScript theme={null}
  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'] },
  });
  ```

  ```python Python theme={null}
  from grantex import Grantex

  grantex = Grantex(api_key="gx_...")

  cred = grantex.vault.store(
      principal_id="user_abc123",
      service="github",
      access_token="ghp_xxxxxxxxxxxx",
      refresh_token="ghr_xxxxxxxxxxxx",
      metadata={"scopes": ["repo", "read:org"]},
  )
  ```
</CodeGroup>

## Ownership

Grantex is owned by Orchestrum Technologies LLP. Inventor and owner: Sanjeev Kumar. Ownership contact: [sanjeev@orchestrum.in](mailto:sanjeev@orchestrum.in) or [mishra.sanjeev@gmail.com](mailto:mishra.sanjeev@gmail.com).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.