# Authentication

This guide covers how to authenticate with the Vilna API, verify webhook signatures, and keep your credentials secure.

## API key authentication

Every request to the Vilna API must include an API key in the `X-Api-Key` header.

### Getting an API key

1. [Sign up](https://app.vilna.io) and create your account.
2. Create a workspace and a project.
3. Generate an API key in the project settings with the permissions you need.


API keys are project-scoped. RPC keys and management keys are workspace-scoped - create them in workspace settings. See the [Dashboard](/guides/dashboard) for details.

### Using the key in requests

curl

```bash
curl "https://api.vilna.io/v1/blockchains" \
  -H "X-Api-Key: your-api-key"
```

TypeScript

```typescript
import { createVilnaClient } from "@vilna/sdk";

const client = createVilnaClient({
  apiKey: "your-api-key",
});

const { data, error } = await client.GET("/blockchains");
```

If the key is missing or invalid, the API returns an [RFC 7807](https://tools.ietf.org/html/rfc7807) error:


```json
{
  "type": "https://docs.vilna.io/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or missing API key."
}
```

## API key types

Vilna uses three types of API keys, each designed for a specific service and scope.

| Type | Prefix | Scope | Used for |
|  --- | --- | --- | --- |
| API key | `vilna_api_` | Project | Platform API access (addresses, transactions, balances) |
| RPC key | `vilna_rpc_` | Workspace | Blockchain node access via Vilna RPC |
| Management key | `vilna_mgt_` | Workspace | Management API (workspaces, projects, members, keys) |


**API keys** are project-scoped. Each key is bound to a single project within a workspace and can only access resources that belong to that project. If you have multiple projects, you need a separate API key for each one.

**RPC keys** and **management keys** are workspace-scoped. They operate across all projects in the workspace. An RPC key grants access to blockchain node endpoints, while a management key allows you to manage workspaces, projects, members, and other keys programmatically.

Each key type carries its own set of permissions that control which operations the key can perform. For example, an API key may have `api:address:read` but not `api:address:write`. See the [authorization reference](/apis/mgmt/authorization) for the full permission matrix.

All three key types are passed in the same `X-Api-Key` header. The gateway identifies the key type from its prefix and routes the request to the correct service automatically.

A key is 40 characters long: the type prefix, 24 random base62 characters, and 6 CRC32 check characters. For example:


```
vilna_api_aBcDeFgHiJkLmNoPqRsTuVwX123456
```

You can create and manage keys through the [Management API](/apis/mgmt/) or the Vilna dashboard.

## Webhook signature verification

Planned feature
Webhook signature verification is not yet available. The API currently delivers webhooks without cryptographic signatures. This feature is planned for an upcoming release.

When Vilna delivers a webhook event, the request includes headers that let you verify authenticity and prevent replay attacks.

### Webhook headers

| Header | Description |
|  --- | --- |
| `X-Webhook-Signature` | HMAC-SHA256 signature of the request body |
| `X-Webhook-Event` | Event type (`transaction_alert` or `test`) |
| `X-Webhook-Idempotency-Key` | Unique delivery ID for deduplication |
| `X-Webhook-Timestamp` | Unix timestamp of when the event was sent |


### Verifying the signature

Construct the signed payload by concatenating the timestamp, a dot (`.`), and the raw request body. Compute an HMAC-SHA256 digest of this payload using your webhook secret as the key, then compare it to the value in `X-Webhook-Signature`.

When you create a notification channel, the API response includes a `secret` field. This is your webhook signing secret - store it securely. You will use it to verify that incoming webhook requests are genuinely from Vilna. The secret is unique per notification channel and is only shown once at creation time.

Secret shown only once
The webhook secret is unique per notification channel and is only displayed at creation time. Store it in a secure secrets manager immediately.


```typescript
import crypto from "node:crypto";

function verifyWebhookSignature(
  body: string,
  signature: string,
  timestamp: string,
  secret: string
): boolean {
  const payload = `${timestamp}.${body}`;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}
```

Always use a constant-time comparison (`timingSafeEqual`) to avoid timing attacks. Including the timestamp in the signed payload prevents replay attacks, since any change to the timestamp invalidates the signature.

### Preventing replay attacks

Check the `X-Webhook-Timestamp` header against the current time. Reject events that are older than a reasonable window (for example, 5 minutes):


```typescript
const MAX_AGE_SECONDS = 300; // 5 minutes

function isTimestampValid(timestamp: string): boolean {
  const eventTime = parseInt(timestamp, 10);
  const now = Math.floor(Date.now() / 1000);
  return Math.abs(now - eventTime) <= MAX_AGE_SECONDS;
}
```

### Ensuring idempotency

Use the `X-Webhook-Idempotency-Key` header to detect and skip duplicate deliveries. Store processed keys in a cache or database and reject any key you have already seen.

## Security best practices

**Never expose keys in frontend code.** API keys grant full access to your project resources. Keep them on the server side only.

**Use environment variables.** Store credentials in environment variables or a secrets manager, not in source code.


```bash
export VILNA_API_KEY="your-api-key"
```


```typescript
const client = createVilnaClient({
  apiKey: process.env.VILNA_API_KEY!,
});
```

**Rotate keys periodically.** If a key is compromised, revoke it immediately through the [dashboard](https://app.vilna.io) or [Management API](/apis/mgmt/) and create a new one.

**Permissions are fixed at creation.** Each key is issued with a frozen permission set. There is no endpoint to change a key's permissions after the fact — if you need to broaden or narrow access, revoke the key and create a new one with the desired permissions.

**Use separate keys per environment.** Maintain different API keys for development, staging, and production so that a leak in one environment does not affect the others.

**Restrict network access.** Where possible, allow-list the IP addresses that your server uses to call the Vilna API.

## Error responses

All authentication and authorization errors follow the [RFC 7807](https://tools.ietf.org/html/rfc7807) `application/problem+json` format:

| Status | Meaning |
|  --- | --- |
| `401` | Missing or invalid API key |
| `403` | Valid key but insufficient permissions |



```json
{
  "type": "https://docs.vilna.io/errors/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "Your API key does not have access to this resource."
}
```

For full details on error handling, see the [Platform API](/apis/platform/).

## Further reading

Quickstart
End-to-end setup walkthrough

Platform API
Complete endpoint documentation

Management API
Workspace and key management endpoints