> ## Documentation Index
> Fetch the complete documentation index at: https://turnkey-0e7c1f5b-zeke-secrets-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Secret Storage

> Import, store, and export arbitrary secrets (passwords, credit cards, API keys) with policy-gated, end-to-end encrypted access.

export const SolutionCard = ({title, description, icon, href}) => {
  return <a href={href} className="not-prose font-normal group ring-0 ring-transparent cursor-pointer block rounded-lg border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-transparent p-5 no-underline hover:border-primary/40 transition-colors">
      <div style={{
    display: 'flex',
    alignItems: 'flex-start',
    gap: '16px'
  }}>
        <img src={`/images/solutions/light/${icon}.svg`} className="tk-card-icon-img block dark:hidden" alt="" />
        <img src={`/images/solutions/dark/${icon}.svg`} className="tk-card-icon-img hidden dark:block" alt="" />
        <div>
          <div className="font-semibold text-sm text-zinc-950 dark:text-white group-hover:text-primary transition-colors">
            {title}
          </div>
          <div className="text-sm text-zinc-500 dark:text-zinc-400 mt-1">
            {description}
          </div>
        </div>
      </div>
    </a>;
};

export const FeatureCard = ({title, description, icon, logo, href}) => {
  return <a href={href} className="not-prose font-normal group ring-0 ring-transparent cursor-pointer block rounded-lg border border-zinc-950/10 dark:border-white/10 bg-white dark:bg-transparent p-5 no-underline hover:border-primary/40 transition-colors">
      <div className="tk-card-row">
        <span className="tk-card-icon-wrap">
          {logo ? <img src={`/images/networks/${logo}.svg`} className="tk-card-network-logo" alt="" /> : <span className="tk-card-icon" style={{
    maskImage: `url(/images/icons/${icon}.svg)`,
    WebkitMaskImage: `url(/images/icons/${icon}.svg)`
  }} />}
        </span>
        <div>
          <div className="font-semibold text-sm text-zinc-950 dark:text-white group-hover:text-primary transition-colors">
            {title}
          </div>
          {description && <div className="text-sm text-zinc-500 dark:text-zinc-400 mt-1">
              {description}
            </div>}
        </div>
      </div>
    </a>;
};

<Info>
  **Closed beta**: the Secrets API is currently in closed beta. [Contact us](https://www.turnkey.com/contact-us) to get onboarded.
</Info>

Turnkey Secrets lets you store arbitrary sensitive data (passwords, credit card details, API keys, SSNs) encrypted end-to-end between your client and Turnkey's [secure enclaves](/security/secure-enclaves). The [policy engine](/features/policies/overview) evaluates every export, so you control exactly who can retrieve a secret, under what conditions, and with how many approvals. We designed the secret storage API for flexibility and programmability.

Plaintext only ever exists inside the enclave and on the client that imported or exported it. Turnkey's coordinator, database, and public API only ever see ciphertext.

## How it works

**Import**: Turnkey mints a single-use ingress target key inside the enclave, signed by the enclave's quorum key. Your client verifies that signature, encrypts the secret to the target key using HPKE, and submits the ciphertext. The enclave decrypts it, re-encrypts it for storage at rest under a quorum-key-derived key, and deletes the ingress key.

**Export**: the export request carries an ephemeral P-256 target public key, and after policy evaluation approves the request, the enclave decrypts the stored secret and re-encrypts it to that key. The target key is fully configurable: it can belong to the requester, to another agent or service, or to a party that isn't an approver at all. Only the holder of the private half can decrypt the result. The export payload is useless to anyone else, including the approvers themselves.

For a batch export, the request succeeds only if every policy evaluation returns `ALLOW`. A `DENY`, or any evaluation without an `ALLOW` outcome, rejects the entire batch. Turnkey never exports part of a batch.

## Static properties

Secrets are created with optional **static properties**: string key-value pairs that are immutably bound to the secret and visible to the policy engine. They let you write export policies against classes of secrets instead of individual IDs:

```json theme={"system"}
{
  "policyName": "Only the payments agent can export credit cards",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(u, u.tags.contains('payment-agent'))",
  "condition": "activity.type == 'ACTIVITY_TYPE_EXPORT_SECRETS' && secret.static_properties['kind'] == 'creditCard'"
}
```

## Importing a secret

The `importSecret` method in [`@turnkey/sdk-server`](/sdks/typescript-sdk) and [`@turnkey/core`](/sdks/typescript-sdk) handles the full flow. It initializes the ingress key, verifies the enclave signature, encrypts the secret, and submits the ciphertext:

```typescript theme={"system"}
const secretId = await turnkey.apiClient().importSecret({
  plaintext: JSON.stringify({ number: "4242...", exp: "11/29", cvv: "123" }),
  name: "corporateVisa",
  staticProperties: {
    kind: "creditCard",
    requiresConsensus: "true",
  },
});
```

For sensitive material you want wiped from memory after encryption, pass a `Uint8Array` instead of a string. The SDK zeroizes the buffer after it produces the ciphertext.

Under the hood this calls [init\_import\_secrets](/api-reference/activities/init-import-secrets) and [import\_secrets](/api-reference/activities/import-secrets).

## Exporting a secret

`exportSecret` generates the ephemeral keypair, submits the export activity, decrypts the result, and zeroizes the key. It is a single call when policy allows the caller to export unilaterally:

```typescript theme={"system"}
const plaintext = await turnkey.apiClient().exportSecret({
  secretId,
});
```

If the export requires additional approvals, `exportSecret` throws a consensus-needed error. For multi-party flows, including multiple agent instances that co-sign the same export with session keys, use the proposal SDK helpers described in [Programmable Credential Access](/solutions/key-management/programmable-credential-access).

## Listing secrets

[list\_secrets](/api-reference/queries/list-secrets) returns metadata: IDs, names, static properties, and creation timestamps:

```typescript theme={"system"}
const { secrets } = await turnkey.apiClient().listSecrets({});
```

## Multi-party approval

Because export is an activity, it composes with everything the policy engine supports: [consensus](/features/policies/overview) across durable users, tag-based approver requirements, and [root quorum](/features/users/root-quorum). Model browser and payment agent roles as separate Turnkey users, then use session keys to authenticate their ephemeral instances. Policy can require both roles to approve before a credit card leaves the enclave, while the payload stays encrypted to only one instance. This makes credential delegation easy to model without treating each ephemeral agent instance as a separate user.

## Security model

Turnkey is a signing and encryption platform running inside secure enclaves, originally built to secure billions of dollars in digital assets. Secret storage is built from the same primitives:

* **End-to-end encryption**: plaintext exists only in enclave memory and on your client. Transport in both directions uses HPKE to single-use P-256 target keys.
* **Authenticated storage**: at-rest ciphertext is AES-256-GCM under a per-secret key derived from the enclave quorum key, with the organization, secret ID, and cipher suite bound into the authenticated data, so no one can substitute ciphertext across secrets or organizations.
* **Signed provenance**: the enclave quorum key signs every stored secret and ingress key. Enclaves refuse anything they didn't produce.
* **Quantum resistant internally, agile in transit**: secrets rest under AES-256-GCM, a quantum resistant cipher. The transport cipher suite is a field in import and export requests, designed to be extended over time, so Turnkey can adopt new transport protocols as they mature.
* **Forward secrecy**: ingress and egress target keys are single-use. Compromising one exposes at most one payload.
* **Full auditability**: every import, export, and approval is an activity that is attributed to the authenticating credential, logged, and queryable.

## Next steps

<div style={{display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '12px'}}>
  <SolutionCard title="Programmable Credential Access" icon="programmable-credential-access" href="/solutions/key-management/programmable-credential-access" description="A password manager built for machines: policy-gated credential access for humans, services, and AI agents." />

  <SolutionCard title="High Security API Key Storage" icon="high-security-api-key-storage" href="/solutions/key-management/high-security-api-key-storage" description="Programmatically store and gate access to your most sensitive API keys." />

  <FeatureCard title="Policy Engine" icon="file-shield-02" href="/features/policies/overview" description="Gate secret export on identity, static properties, approval counts, and tags." />

  <FeatureCard title="Secure Enclaves" icon="cpu-chip-01" href="/security/secure-enclaves" description="How Turnkey protects secrets inside hardware-backed enclaves." />
</div>
