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

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