> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dualship.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets

> Securely store and use sensitive data like API keys and credentials

Secrets allow you to securely store sensitive data like API keys, tokens, and credentials that your flows need to access external services. Once stored, secrets are available in your flows using template expressions.

## Overview

Every project has its own isolated secret storage. This ensures complete separation between projects, so secrets from one project are never accessible to another.

**Key security features:**

* **Encryption at rest** - All secrets are encrypted before storage
* **Isolated storage** - Each project has its own dedicated secret vault
* **Masked in logs** - Secret values are never written to execution logs
* **Masked in API responses** - API responses always display `********` instead of actual values
* **Automatic cleanup** - Secrets are permanently deleted when a project is deleted
* **Automatic rotation** - Encryption keys are rotated automatically to maintain security

## Using Secrets in Flows

Access your secrets in any flow configuration using the `{{env.KEY_NAME}}` template syntax.

### In HTTP Node Headers

```json theme={null}
{
  "id": "call_stripe",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "https://api.stripe.com/v1/charges",
    "headers": {
      "Authorization": "Bearer {{env.STRIPE_API_KEY}}",
      "Content-Type": "application/x-www-form-urlencoded"
    },
    "body": {
      "amount": "{{request.body.amount}}",
      "currency": "usd"
    }
  }
}
```

### In URLs

```json theme={null}
{
  "url": "https://{{env.API_HOST}}/v1/users"
}
```

### In Request Bodies

```json theme={null}
{
  "body": {
    "api_key": "{{env.THIRD_PARTY_KEY}}",
    "webhook_url": "{{env.WEBHOOK_CALLBACK_URL}}"
  }
}
```

### With Default Values

Use the `default` pipe to provide fallback values:

```json theme={null}
{
  "url": "{{env.API_BASE_URL | default:https://api.example.com}}/endpoint"
}
```

## Common Use Cases

### External API Authentication

```json theme={null}
{
  "headers": {
    "Authorization": "Bearer {{env.API_TOKEN}}",
    "X-Api-Key": "{{env.API_KEY}}"
  }
}
```

### Database Connection Strings

Store complete connection URLs as secrets:

```
Key: DATABASE_URL
Value: postgres://user:password@host:5432/database
```

### Webhook Secrets

Store secrets used for webhook signature verification:

```
Key: WEBHOOK_SECRET
Value: whsec_xxxxxxxxxxxxxxx
```

### Third-Party Service Credentials

```
Key: SENDGRID_API_KEY
Key: TWILIO_AUTH_TOKEN
Key: AWS_SECRET_ACCESS_KEY
```

## Best Practices

### Naming Conventions

Use descriptive, consistent names:

| Pattern           | Example          | Use Case           |
| ----------------- | ---------------- | ------------------ |
| `SERVICE_API_KEY` | `STRIPE_API_KEY` | API keys           |
| `SERVICE_SECRET`  | `WEBHOOK_SECRET` | Shared secrets     |
| `SERVICE_TOKEN`   | `GITHUB_TOKEN`   | Access tokens      |
| `SERVICE_URL`     | `DATABASE_URL`   | Connection strings |

### Environment-Specific Secrets

For different environments (staging, production), use separate Dualship projects with their own secrets. This ensures complete isolation between environments.

## Security Guarantees

| Aspect        | Protection                                            |
| ------------- | ----------------------------------------------------- |
| Storage       | Encrypted at rest in a dedicated secrets vault        |
| Transmission  | All API calls use HTTPS                               |
| Isolation     | Each project has completely separate secret storage   |
| Access        | Secrets only accessible to authorized project members |
| Logging       | Values never appear in execution logs                 |
| API Responses | Values always masked as `********`                    |
| Deletion      | Permanently removed when project is deleted           |

## Caching

For performance, secrets are cached with automatic invalidation. When you create, update, or delete a secret, the cache is cleared and new values take effect immediately.

## Limits

| Plan  | Secrets Limit |
| ----- | ------------- |
| Free  | Unlimited     |
| Hobby | Unlimited     |
| Pro   | Unlimited     |

All plans include unlimited secrets at no additional cost.

## Related

* [Template Expressions](/reference/templates) - How to use `{{env.KEY}}` syntax
* [Project Settings](/project-settings) - Log masking for additional security
* [HTTP Node](/nodes/http) - Making authenticated API calls
