Skip to Content
CLI & DevOpsCommands

Commands

Complete reference for TrustPin CLI commands.

Authentication

configure

Configure the CLI with your Personal Access Token.

trustpin-cli configure

Interactive prompt:

$ trustpin-cli configure API Base URL (https://api.trustpin.cloud): https://api.trustpin.cloud API Token: tp_your_personal_access_token_here Configuration saved successfully!

Get your Personal Access Token:

  1. Visit https://app.trustpin.cloud/account/access-tokens 
  2. Click Create Token
  3. Copy the token (it starts with tp_)
  4. Use it with trustpin-cli configure

Token permissions:

  • User-scoped: Access all projects you have permission to view
  • Can expire: Create a new token if yours expires

Reset configuration:

If you need to reconfigure or clear your credentials:

# Remove configuration rm -rf ~/.trustpin/ # Configure again trustpin-cli configure

Project Management

projects list

List all projects you have access to.

trustpin-cli projects list [--output json]

Examples:

# Human-readable format (default) $ trustpin-cli projects list ═══ Projects (2) ═══ ── TrustPin Mobile App ── ID: df9964a9-66bf-4673-9743-adee9ce6213e Type: Managed CDN with Cloud Keys Organization: Personal Organization Domains: 4 ── API Gateway ── ID: 99acf096-79b9-4fa6-a115-14b35b224839 Type: Managed CDN with Bring Your Own Keys Organization: Personal Organization Domains: 2
# JSON format for automation $ trustpin-cli projects list --output json { "status": "success", "operation": "projects-list", "data": { "projects": [ { "id": "df9964a9-66bf-4673-9743-adee9ce6213e", "name": "TrustPin Mobile App", "organization_id": "fb52418e-b5ae-4bff-b973-6da9ae07ba00", "organization_name": "Personal Organization", "type": "Managed CDN with Cloud Keys", "domains_count": 4 } ] } }

Use with jq:

# Get all project IDs trustpin-cli projects list --output json | jq -r '.data.projects[].id' # Get project names trustpin-cli projects list --output json | jq -r '.data.projects[].name'

projects upsert

Add or update a certificate pin for a domain in your project configuration.

trustpin-cli projects upsert <organization-id> <project-id> \ --domain <domain-name> \ --pin <type>:<value> \ [--expires <ISO8601-datetime>] \ [--dry-run] \ [--output json]

Parameters:

ParameterRequiredDescription
<organization-id>YesOrganization UUID
<project-id>YesProject UUID
--domainYesDomain name (e.g., api.example.com)
--pinYesPin in format <type>:<value>
--expiresNoExpiration date in ISO 8601 format
--dry-runNoPreview changes without applying them
--outputNoOutput format: human (default) or json

Pin Types:

TypeDescriptionUse Case
sha256Certificate SHA-256 fingerprintMust update pin on every certificate renewal
sha512Certificate SHA-512 fingerprintMust update pin on every certificate renewal
spki-sha256SPKI SHA-256 fingerprintRecommended - OWASP best practice
spki-sha512SPKI SHA-512 fingerprintMaximum security + OWASP best practice

Why SPKI is recommended: SPKI (Subject Public Key Info) pins the public key, not the certificate. This is the OWASP-recommended approach for certificate pinning. When combined with TrustPin’s dynamic pin updates, it enables zero-downtime certificate rotation regardless of whether keys change during renewal.

Key Reuse (Optional): If you reuse the same private key during certificate renewal (e.g., certbot renew --reuse-key), the SPKI pin remains unchanged. However, most managed certificate services (AWS ACM, Let’s Encrypt default, Cloudflare) generate new key pairs on renewal, which changes the SPKI pin—but TrustPin’s dynamic updates handle this seamlessly.

Upsert Behavior:

The command is idempotent and follows these rules:

ScenarioActionResponse
Domain exists, pin exists, same expirationNo-op"action": "no_change"
Domain exists, pin exists, different expirationUpdate"action": "updated"
Domain exists, pin doesn’t existAdd"action": "added"
Domain doesn’t existCreate + Add"action": "added"

Pin matching: Pins are matched by type + value. Expiration is not part of the match key.

Examples:

Extract and add SPKI SHA-256 pin:

# Extract SPKI SHA-256 from certificate SPKI_SHA256=$(openssl x509 -in cert.pem -pubkey -noout | \ openssl pkey -pubin -outform der | \ openssl dgst -sha256 -binary | \ base64) # Extract expiration date EXPIRES=$(openssl x509 -in cert.pem -noout -enddate | \ cut -d= -f2 | \ xargs -I{} date -d "{}" -u +%Y-%m-%dT%H:%M:%SZ) # Add pin to project trustpin-cli projects upsert \ fb52418e-b5ae-4bff-b973-6da9ae07ba00 \ 9caaea0a-013e-4e7b-80ea-cee6bfb52b36 \ --domain api.example.com \ --pin spki-sha256:$SPKI_SHA256 \ --expires $EXPIRES \ --output json

Output:

{ "status": "success", "operation": "upsert", "domain": "api.example.com", "action": "added", "pin": { "type": "spki-sha256", "value": "oxVSdCLgthL3M5Vnnzepq8WWlkUfRPYkpjLpm+wn+1o=", "expires_at": "2026-04-13T08:37:02Z" }, "config_version": { "before": 2, "after": 3 } }

Dry run to preview changes:

trustpin-cli projects upsert \ fb52418e-b5ae-4bff-b973-6da9ae07ba00 \ 9caaea0a-013e-4e7b-80ea-cee6bfb52b36 \ --domain api.example.com \ --pin spki-sha256:$SPKI_SHA256 \ --expires 2026-04-13T08:37:02Z \ --dry-run

Output (dry run):

Dry run mode enabled - no changes will be made Would send PATCH request to: /organizations/fb52418e-b5ae-4bff-b973-6da9ae07ba00/projects/9caaea0a-013e-4e7b-80ea-cee6bfb52b36/config Request body: { "domain": "api.example.com", "pin": { "type": "spki-sha256", "value": "oxVSdCLgthL3M5Vnnzepq8WWlkUfRPYkpjLpm+wn+1o=", "expires_at": "2026-04-13T08:37:02Z" } }

Update expiration date only:

# Pin already exists, just update the expiration trustpin-cli projects upsert \ fb52418e-b5ae-4bff-b973-6da9ae07ba00 \ 9caaea0a-013e-4e7b-80ea-cee6bfb52b36 \ --domain api.example.com \ --pin spki-sha256:oxVSdCLgthL3M5Vnnzepq8WWlkUfRPYkpjLpm+wn+1o= \ --expires 2027-06-01T00:00:00Z

Output:

{ "status": "success", "operation": "upsert", "domain": "api.example.com", "action": "updated", "pin": { "type": "spki-sha256", "value": "oxVSdCLgthL3M5Vnnzepq8WWlkUfRPYkpjLpm+wn+1o=", "expires_at": "2027-06-01T00:00:00Z" }, "config_version": { "before": 3, "after": 4 } }

Add certificate SHA-256 pin:

# Extract certificate SHA-256 CERT_SHA256=$(openssl x509 -in cert.pem -outform der | \ openssl dgst -sha256 -binary | \ base64) trustpin-cli projects upsert \ fb52418e-b5ae-4bff-b973-6da9ae07ba00 \ 9caaea0a-013e-4e7b-80ea-cee6bfb52b36 \ --domain cdn.example.com \ --pin sha256:$CERT_SHA256 \ --expires 2026-04-13T08:37:02Z

Important Notes:

  1. Configuration is not published yet - After upserting, you must run projects sign to publish changes to the CDN
  2. Multiple upserts before signing - You can upsert multiple domains/pins before signing once
  3. Idempotent operation - Safe to run multiple times; won’t duplicate pins
  4. Version tracking - Each upsert increments the configuration version
  5. No waiting period - Upsert is instantaneous; only signing publishes to CDN

Common Use Cases:

1. Add backup pin before certificate rotation:

# Add new certificate's pin while old cert is still active trustpin-cli projects upsert $ORG_ID $PROJECT_ID \ --domain api.example.com \ --pin spki-sha256:$NEW_SPKI \ --expires 2027-06-01T00:00:00Z # Sign and publish trustpin-cli projects sign $ORG_ID $PROJECT_ID --password $MASTER_PASSWORD # Wait 24-48 hours for mobile apps to fetch new config # Then deploy new certificate to servers

2. Update multiple domains with wildcard certificate:

# Same pin for multiple domains for DOMAIN in api.example.com cdn.example.com www.example.com; do trustpin-cli projects upsert $ORG_ID $PROJECT_ID \ --domain $DOMAIN \ --pin spki-sha256:$SPKI \ --expires $EXPIRES done # Sign once after all updates trustpin-cli projects sign $ORG_ID $PROJECT_ID --password $MASTER_PASSWORD

3. Certificate renewal with same key (SPKI unchanged):

# Only expiration changes, SPKI remains the same trustpin-cli projects upsert $ORG_ID $PROJECT_ID \ --domain api.example.com \ --pin spki-sha256:$EXISTING_SPKI \ --expires $NEW_EXPIRES # Sign and deploy immediately (no waiting needed - pin unchanged) trustpin-cli projects sign $ORG_ID $PROJECT_ID --password $MASTER_PASSWORD

Exit Codes:

CodeMeaningExample
0Success or no-opPin added, updated, or unchanged
2API errorHTTP 401, 404, 500
4Validation errorInvalid domain, pin format, or type
99Unexpected errorNetwork timeout, file I/O error

See Also:


Configuration Signing

projects sign (Cloud Keys)

Sign and publish project configuration using cloud-managed keys.

trustpin-cli projects sign <organization-id> <project-id>

Example:

$ trustpin-cli projects sign fb52418e-b5ae-4bff-b973-6da9ae07ba00 df9964a9-66bf-4673-9743-adee9ce6213e Master password: **** [1/5] Getting project information Project: TrustPin Mobile App (Managed CDN with Cloud Keys) [2/5] Loading project configuration Configuration loaded with 4 domains [3/5] Preparing private key Using cloud-managed private key [4/5] Creating and signing JWT JWT signed successfully [5/5] Uploading signed configuration Configuration published successfully!

The configuration is now live and SDKs will use it immediately.


projects sign (BYOK)

Sign and publish project configuration using your own private key (Bring Your Own Key).

trustpin-cli projects sign <organization-id> <project-id> --private-key <path-to-pem-file>

Requirements:

  • Private key must be in PEM format
  • Private key can be password-protected (you’ll be prompted)

Example:

$ trustpin-cli projects sign fb52418e-b5ae-4bff-b973-6da9ae07ba00 99acf096-79b9-4fa6-a115-14b35b224839 --private-key ./my-private-key.pem Master password: **** Private key password: **** [1/5] Getting project information Project: API Gateway (Managed CDN with Bring Your Own Keys) [2/5] Loading project configuration Configuration loaded with 2 domains [3/5] Preparing private key Reading private key from file: ./my-private-key.pem [4/5] Creating and signing JWT JWT signed successfully [5/5] Uploading signed configuration Configuration published successfully!

What happens on failure:

If signing fails, the previous configuration remains active. Your users are not affected. You can retry signing at any time.


projects jws

Fetch the published JWS (JSON Web Signature) configuration from the CDN.

This command retrieves the currently published certificate pinning configuration that mobile applications are fetching. The JWS is the signed configuration that was published by the sign command.

trustpin-cli projects jws <organization-id> <project-id> [flags]

Flags:

FlagDescription
--decodeDecode and display JWS header and payload
--verifyVerify JWS signature using public key from CDN
--output-file <path>Save JWS to file

Use cases:

  • Verify what configuration is currently published
  • Debug mobile app pinning issues
  • Validate that sign successfully published the configuration
  • Download the JWS for testing, archival, or self-hosted CDN deployment

Examples:

Fetch raw JWS (default):

$ trustpin-cli projects jws fb52418e-b5ae-4bff-b973-6da9ae07ba00 df9964a9-66bf-4673-9743-adee9ce6213e eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb21haW5zIjp7ImFwaS5leGFtcGxlLmNvbSI6W3sidHlwZSI6InNwa2ktc2hhMjU2IiwidmFsdWUiOiJveFZTZENMZ3RoTDNNNVZubnplcHE4V1dsa1VmUlBZa3BqTHBtK3duKzFvPSIsImV4cGlyZXNfYXQiOiIyMDI2LTA0LTEzVDA4OjM3OjAyWiJ9XX0sImlhdCI6MTczODk4NzIwMH0.kG7z2x3nF4mB8qW9pL5jD3rC6vT8sY1eN4hK2mO9iU7lP4aQ6wX8bV9nE5cR3fJ2dT7gH1sM4kL6pO8jU9qW3e

Verify JWS signature:

$ trustpin-cli projects jws fb52418e-b5ae-4bff-b973-6da9ae07ba00 df9964a9-66bf-4673-9743-adee9ce6213e --verify JWS signature valid Signed with algorithm: ES256 (ECDSA P-256) Public key verified from CDN

Decode and display payload:

$ trustpin-cli projects jws fb52418e-b5ae-4bff-b973-6da9ae07ba00 df9964a9-66bf-4673-9743-adee9ce6213e --decode ═══ JWS Header ═══ { "alg": "ES256", "typ": "JWT" } ═══ JWS Payload ═══ { "domains": { "api.example.com": [ { "type": "spki-sha256", "value": "oxVSdCLgthL3M5Vnnzepq8WWlkUfRPYkpjLpm+wn+1o=", "expires_at": "2026-04-13T08:37:02Z" } ] }, "iat": 1738987200 } Current DB Version: 3 Published Version: 3

Save JWS to file:

$ trustpin-cli projects jws fb52418e-b5ae-4bff-b973-6da9ae07ba00 df9964a9-66bf-4673-9743-adee9ce6213e --output-file config.jws JWS saved to config.jws

Pipe to mobile app simulator:

$ trustpin-cli projects jws fb52418e-b5ae-4bff-b973-6da9ae07ba00 df9964a9-66bf-4673-9743-adee9ce6213e | ./test-mobile-app Testing certificate pinning with config... All domains validated successfully

Common workflows:

1. Verify deployment after signing:

# Sign configuration trustpin-cli projects sign $ORG_ID $PROJECT_ID --password $MASTER_PASSWORD # Verify it's published and valid trustpin-cli projects jws $ORG_ID $PROJECT_ID --verify

2. Archive configurations for compliance:

# Save with timestamp trustpin-cli projects jws $ORG_ID $PROJECT_ID \ --output-file "archive/config-$(date +%Y%m%d-%H%M%S).jws"

3. Deploy to self-hosted CDN:

# Download signed JWS trustpin-cli projects jws $ORG_ID $PROJECT_ID --output-file config.jws # Verify integrity trustpin-cli projects jws $ORG_ID $PROJECT_ID --verify # Upload to your CDN aws s3 cp config.jws s3://your-bucket/trustpin/config.jws

Exit Codes:

CodeMeaning
0Success
1No JWS published on CDN
2API error
5JWS signature verification failed
99Unexpected error

See Also:


Output Formats

All commands support two output formats:

Human-Readable (Default)

Formatted output with colors and progress indicators, perfect for interactive use.

trustpin-cli projects list

JSON

Machine-readable output for automation and CI/CD pipelines.

trustpin-cli projects list --output json

JSON response structure:

{ "status": "success", "operation": "command-name", "data": { // Command-specific data } }

Getting Help

View help for any command:

# General help trustpin-cli --help # Command-specific help trustpin-cli projects --help trustpin-cli projects sign --help