NewInstance Documentation
View as Markdown

Secret Manager

Secret Manager keeps API keys, database URLs and other secrets end-to-end encrypted. Store them once and 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

ConceptWhat it is
AppA container of secrets (one service or product), identified by appId.
Environmentdevelopment / staging / production; each variable belongs to one.
App SecretClient-held key that unwraps the MEK. Never sent to the API.
MEKThe key your variables are actually encrypted with, fetched wrapped and unwrapped locally.
API keyA normal platform key with secret-read scope. It authorizes fetching ciphertext, nothing more.

Three ways to consume secretslink

  1. Dashboard: create apps, add variables, share across apps with inheritance links.
  2. This REST API: your service fetches the wrapped MEK once and the encrypted variables per environment, then decrypts in memory.
  3. The nism CLI: 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:

  1. Store secrets in the merchant dashboard at /dashboard/org/[orgId]/secret-manager
  2. Your app fetches the encrypted master key (MEK) at startup
  3. Decrypt the MEK using your App Secret (stored securely server-side)
  4. 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

Get encrypted master key

GET/api/v1/secret-manager/apps/{appId}/master-key

Returns an app's Master Encryption Key (MEK), still encrypted under your App Secret.

Scope: full-access or secret-read

appId in the path is the App ID from the Secret Manager dashboard (set it as {{appId}} in your environment).

Unwrap encryptedMasterKey locally with your App Secret, using masterKeyIV and masterKeyTag (AES-256-GCM). The nismsdk package does this for you with decryptMasterKey. Each call counts toward your Secret Manager request allowance, and 429 means the allowance is used up under a hard limit.

Authorization

x-api-keyAPI key · headerrequired

Parameters

appIdpath · stringrequireddefault:

Responses

200Encrypted MEK
400App secret not set up yet
401Invalid or missing API key
403Missing permission scope
404App not found
429Rate limited
curl -X GET 'https://api.newinstance.cloud/api/v1/secret-manager/apps/{appId}/master-key' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "success": true,
  "data": {
    "appId": "66f1a2b3c4d5e6f7a8b9c0a1",
    "appName": "checkout-api",
    "encryptedMasterKey": "k3J9vQx0bW1lc3NhZ2UtY2lwaGVydGV4dA==",
    "masterKeyIV": "q8Zx4Lm2Tn9Pw1Rs",
    "masterKeyTag": "Vb7nC2xQ9mL4kP0sR6tY1w=="
  }
}

Get encrypted variables

GET/api/v1/secret-manager/apps/{appId}/variables

Returns an app's environment variables for one environment, each value still encrypted under the app's MEK.

Scope: full-access or secret-read

appId in the path is the App ID from the Secret Manager dashboard.

Decrypt each value locally with the MEK from Get encrypted master key, using the variable's iv and tag (AES-256-GCM). The nismsdk package does this for you with decryptWithMasterKey. An environment with no variables answers 200 with an empty variables list.

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.js

Commands: 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.

Authorization

x-api-keyAPI key · headerrequired

Parameters

environmentquery · stringdefault:

Optional. development, staging or production. Defaults to development.

appIdpath · stringrequireddefault:

Responses

200Encrypted variables
401Invalid or missing API key
403Missing permission scope
404App not found
curl -X GET 'https://api.newinstance.cloud/api/v1/secret-manager/apps/{appId}/variables?environment=production' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "success": true,
  "data": {
    "appId": "66f1a2b3c4d5e6f7a8b9c0a1",
    "environment": "production",
    "variables": [
      {
        "id": "66f1a2b3c4d5e6f7a8b9c0b1",
        "key": "DATABASE_URL",
        "value": "Zm9vYmFyLWNpcGhlcnRleHQtMQ==",
        "type": "String",
        "description": "Primary Postgres connection string",
        "environment": "production",
        "isInherited": false,
        "sourceAppId": null,
        "version": 3,
        "iv": "p2Lm8Qx1Zt7Rw4Ns",
        "tag": "Hc5vB8nM2xK9qL1sT4wY7g=="
      },
      {
        "id": "66f1a2b3c4d5e6f7a8b9c0b2",
        "key": "STRIPE_SECRET_KEY",
        "value": "Zm9vYmFyLWNpcGhlcnRleHQtMg==",
        "type": "String",
        "description": "Stripe live secret key",
        "environment": "production",
        "isInherited": false,
        "sourceAppId": null,
        "version": 1,
        "iv": "Tn6Wq3Lx9Zp2Rm5K",
        "tag": "Ld8sF3gH6jK1mN4pQ7rT0w=="
      }
    ]
  }
}