SDKs + CLI v0.5: Policies, Vault, and Ledger everywhere
The Policies, Vault, and Ledger endpoints we shipped this week are now first-class citizens in every official client — npm, PyPI, NuGet, and the postq Go CLI. Same surface, idiomatic in each language, one version bump.
Over the last few days we shipped three real product surfaces in quick succession: PostQ Vault (managed hybrid signing with BYOK), PostQ Ledger (per-org Merkle audit log), and Policies (typed, machine-evaluable rules enforced on every POST /v1/sign). All three are live on the API. Today we’re catching up the clients.
v0.5.0 of @postq/sdk, postq-sdk, PostQ.Sdk, and the postq Go CLI is out. The new endpoints are wrapped in every language with the same shape, the same error model, and the same name. If you can do it in the dashboard, you can now do it from a script in any of four languages.
What’s new
- Policies —
list / get / create / update / delete, plusenable / disableon the CLI. The typedruleobject lets you pin an org torequire_hybrid, a minimum ML-DSA NIST level, an algorithm allowlist or blocklist, and a max payload size — all enforced server-side before/v1/signever touches a key. - Vault settings —
getSettings / putSettings / clearSettings(CLI:postq vault settings show / put / clear) so you can flip an org betweenenv-managed,aws-kms, andazure-kvKEK providers from CI. - Ledger —
entries / append / checkpoints / latestCheckpoint / seal / proof / bundle. The CLI gets the matching subcommands plus the existing offlinepostq ledger verify bundle.jsonfrom yesterday’s launch. - Hybrid keys —
rotateandauditare now on every client. Old key material stays verifiable; the audit feed is just a typed view over the org ledger filtered to one key id. - BYOK on key creation — the new
kekProvider,keyProvider, andpqProviderfields onHybridKeyCreateInputlet a single call mint a key that lives entirely in your AWS KMS / Azure Key Vault / Azure Managed HSM — no second round-trip through the dashboard. - ECDSA-P256 hybrid algorithms — the
HybridAlgorithmunion now also acceptsmldsa44+ecdsa-p256,mldsa65+ecdsa-p256, andmldsa87+ecdsa-p256, for orgs whose KMS only signs with NIST P-256.
Same surface, four languages
Here’s the same flow — create a policy, sign through it, then download a verifiable bundle — in each client.
TypeScript
import { PostQ } from "@postq/sdk";
const pq = new PostQ({ apiKey: process.env.POSTQ_API_KEY! });
// 1. Pin the org to hybrid algorithms only.
await pq.policies.create({
name: "require-hybrid",
rule: { operations: ["sign"], action: "deny", algorithms: ["ed25519"] },
});
// 2. Sign — server enforces the policy before touching the key.
const sig = await pq.sign({
keyId: "key_…",
payload: new TextEncoder().encode("ship it"),
});
// 3. Seal the ledger and pull a verifiable bundle.
await pq.ledger.seal();
const bundle = await pq.ledger.bundle();
console.log(bundle.entries.length, "entries,", bundle.checkpoints.length, "checkpoints");Python
from postq import PostQ
pq = PostQ(api_key="pq_live_...")
pq.policies.create(
name="require-hybrid",
rule={"operations": ["sign"], "action": "deny", "algorithms": ["ed25519"]},
)
sig = pq.sign(key_id="key_...", payload=b"ship it")
pq.ledger.seal()
bundle = pq.ledger.bundle()
print(len(bundle.entries), "entries,", len(bundle.checkpoints), "checkpoints").NET
using PostQ;
using var pq = new PostQClient(new PostQClientOptions { ApiKey = "pq_live_..." });
await pq.Policies.CreateAsync(new PolicyCreateInput {
Name = "require-hybrid",
Rule = new PolicyRule {
Operations = new[] { "sign" },
Action = "deny",
Algorithms = new[] { "ed25519" },
},
});
var sig = await pq.SignAsync(new HybridSignInput {
KeyId = "key_...",
Payload = System.Text.Encoding.UTF8.GetBytes("ship it"),
});
await pq.Ledger.SealAsync();
var bundle = await pq.Ledger.BundleAsync();
Console.WriteLine($"{bundle.Entries.Count} entries, {bundle.Checkpoints.Count} checkpoints");Go CLI
# Create the policy from a JSON file.
cat > rule.json <<EOF
{ "operations": ["sign"], "action": "deny", "algorithms": ["ed25519"] }
EOF
postq policies create --name require-hybrid --rule @rule.json
# Sign normally — server enforces the policy.
postq sign --key key_... --in artifact.tar.gz --out artifact.sig
# Seal + download a verifiable bundle, then verify it offline.
postq ledger seal
postq ledger bundle --out bundle.json
postq ledger verify bundle.jsonWhy this matters for CI
The CLI’s job is to be a five-line gate. With v0.5, it’s enough by itself to sign a release artifact under a policy your security team owns, append a custom event to the org ledger, and download a fresh bundle that any auditor can re-verify offline with the same binary. No SDK install, no language runtime, no CGO — just one static Go binary per OS/arch.
The SDKs are for everything else: signing services, internal dashboards, policy provisioners, custom scanners. They share the exact same envelope shape and error types as the CLI talks to, so you can mix and match without surprises.
Install / upgrade
# JS / TS
npm i @postq/sdk@latest
# Python
pip install -U postq-sdk
# .NET
dotnet add package PostQ.Sdk --version 0.5.0
# Go CLI
brew upgrade postqdev/tap/postq
# or: go install github.com/postqdev/postq-cli/cmd/postq@latestWhat’s next
- Async iterators over
ledger.entriesandpolicies.list, matching the cursor-paginatediterAllhelpers we already ship for scans / assets / keys. - Server-side rendering of policy simulation — ask “would this sign call have been blocked?” without actually signing.
- Witness co-signing helpers in the SDKs so you can verify a ledger STH against an external witness, not just PostQ.
As always, file an issue or a PR — the SDKs and CLI are open source under MIT, and the contract is openapi.yaml.