Secret Manager
Secret Manager is the New Instance end-to-end-encrypted configuration product: store API keys, database URLs and other secrets once, fetch them at runtime everywhere - while the platform itself can never read them.
The zero-knowledge modellink
Encryption happens on your side. Every value is encrypted client-side with AES-256-GCM under a per-app Master Encryption Key (MEK); the MEK itself is stored wrapped (encrypted) under your App Secret, which never leaves your machines. The server holds ciphertext + IVs + auth tags - nothing decryptable. Losing the App Secret means the data is unrecoverable by design.
Conceptslink
| Concept | What it is |
|---|---|
| App | A container of secrets (one service or product), identified by appId. |
| Environment | development / staging / production - each variable belongs to one. |
| App Secret | Client-held key that unwraps the MEK. Never sent to the API. |
| MEK | The key your variables are actually encrypted with - fetched wrapped, unwrapped locally. |
| API key | A normal platform key with secret-read scope - it authorises fetching ciphertext, nothing more. |
Three ways to consume secretslink
- Dashboard - create apps, add variables, share across apps with inheritance links.
- This REST API - your service fetches the wrapped MEK once and the encrypted variables per environment, then decrypts in memory.
- The
nismCLI - wraps the whole fetch + decrypt flow for local dev and CI (guide below).
Using this APIlink
Fetch encrypted secrets at runtime without hardcoding them in your application.
Scope required: full-access or secret-read
All requests use: x-api-key: {{apiKey}}
How it works:
- Store secrets in the merchant dashboard at
/dashboard/org/[orgId]/secret-manager - Your app fetches the encrypted master key (MEK) at startup
- Decrypt the MEK using your App Secret (stored securely server-side)
- Fetch encrypted variables; decrypt them locally with the MEK
Secrets are never returned in plaintext - everything is encrypted in transit and at rest.
App Secret vs API key
- The App Secret is a per-app value shown once in the dashboard. It is used to decrypt the MEK client-side.
- The API key (
x-api-key) is the central key that authorises the fetch. Both are required.
Rate limit: 50 requests/hour for GET master-key
/api/v1/secret-manager/apps/master-keyGet encrypted master key
Fetch the encrypted Master Encryption Key (MEK) for an app.
Scope: full-access or secret-read
Path param: appId - the App ID from the secret manager dashboard (set as {{appId}} in your environment)
Success - 200 OK
{
"encryptedMek": "<base64-encoded-encrypted-key>",
"algorithm": "AES-256-GCM",
"kdfAlgorithm": "HKDF-SHA256"
}Decrypt the MEK using your App Secret:
const mek = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: decodeBase64(iv) },
await deriveKey(appSecret), // HKDF-SHA256
decodeBase64(encryptedMek)
);Common errors
401- invalid API key403- key lackssecret-readscope404- app not found429- rate limited (50 req/hour)
Headers
x-api-keyResponses
200 – Encrypted MEK
{
"encryptedMek": "base64encodedEncryptedKeyHere==",
"algorithm": "AES-256-GCM",
"kdfAlgorithm": "HKDF-SHA256"
}https://api.newinstance.cloud/api/v1/secret-manager/apps/master-keyHeaders
x-api-keyCode samples
curl -X GET 'https://api.newinstance.cloud/api/v1/secret-manager/apps/master-key'/api/v1/secret-manager/apps/variablesGet encrypted variables
Fetch encrypted environment variables for an app.
Scope: full-access or secret-read
Path param: appId - App ID from dashboard
Query param: environment (optional) - development | staging | production (default: development)
Success - 200 OK
{
"environment": "production",
"variables": [
{ "key": "DATABASE_URL", "encryptedValue": "<base64>", "iv": "<base64>" },
{ "key": "STRIPE_SECRET_KEY", "encryptedValue": "<base64>", "iv": "<base64>" }
]
}Decrypt each variable using the MEK from GET master-key:
const plaintext = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: decodeBase64(variable.iv) },
mek,
decodeBase64(variable.encryptedValue)
);Common errors
401- invalid API key403- key lackssecret-readscope404- app not found or no variables for this environment
The nism CLI (recommended for local dev and CI)link
The published CLI/SDK nismsdk (Node 18+, binaries nism and nismsdk) wraps the fetch + local-decrypt flow; plaintext never transits the platform.
npm i -g nismsdk # or: npx nismsdk <command>
nism setup # store appId / orgId / apiKey in ~/.nism/config.json
nism verify # fetch, decrypt and confirm values are readable
nism load --environment production --create-env .env
eval "$(nism env --appSecret "$NISM_APP_SECRET" --format shell)" && node server.jsCommands: load (the default when no subcommand is given; flags include --environment, --create-env <file>, --env-set-name (default default) and --system-level), setup, config [--show-secrets], env (prints to stdout for piping; fish shells get set -gx), verify. nism does not wrap or spawn your process: to inject secrets into a command, eval the env output first as shown.
Credentials resolve in order: CLI flags, then NISM_* env vars, then legacy NEW_INSTANCE_* env vars, then ~/.nism/config.json, then an interactive prompt. The App Secret is never written to the config file: supply it per run or via NISM_APP_SECRET. Point at the live platform with NISM_GRAPHQL_URL=https://service.newinstance.cloud/service (the built-in default targets a local dev server, so production runs must set this).
Load flags (defaults): --environment development, --format dotenv|json|shell, --output <file>, --bridge true with --bridge-storage-dir ~/.nism, --shell-integration true (detects bash, zsh, fish, ksh, dash), --auto-add-to-profile, --ide-integration, --create-env [file] (a bare flag means .env), --silent, --debug.
Bridge files in ~/.nism: <environment>.json and ide.env at mode 0600, load-<environment>.sh at 0700, config.json at 0600. --auto-add-to-profile appends a marked source block to the matching shell profile. --create-env writes into the current directory with default permissions, unlike the 0600 bridge files, so gitignore the output.
CI: npx nismsdk load --silent --create-env .env with NISM_* repository secrets; add --no-bridge in Docker builds.
Programmatic use (same package): loadSecrets(), injectSecrets(), NismGraphQLClient, decryptMasterKey, decryptWithMasterKey.
Troubleshooting: an invalid App Secret fails the key check; "all variables failed to decrypt" means the right app but the wrong secret; authentication failures point at the API key or org; a missing inheritance link key surfaces when a linked app was unshared; ECONNREFUSED means the GraphQL URL is wrong or unreachable. Re-run with --debug.
Headers
x-api-keyParameters
environmentquerystringdefault: development | staging | production (default: development)Responses
200 – Encrypted variables
{
"environment": "production",
"variables": [
{
"key": "DATABASE_URL",
"encryptedValue": "base64ciphertext==",
"iv": "base64iv=="
},
{
"key": "STRIPE_SECRET_KEY",
"encryptedValue": "base64ciphertext2==",
"iv": "base64iv2=="
}
]
}https://api.newinstance.cloud/api/v1/secret-manager/apps/variablesQuery parameters
environmentHeaders
x-api-keyCode samples
curl -X GET 'https://api.newinstance.cloud/api/v1/secret-manager/apps/variables'