Skip to content
CredenShare
SDKs

SDKs

Official CredenShare clients for Node, Python, Go and Rust — they perform the encryption, so you pass plaintext and get back a link.

There are four official clients: Node, Python, Go and Rust.

They are not thin wrappers around the REST API. The API accepts ciphertext and returns a short code, which means calling it directly obliges you to implement AES-256-GCM, HKDF, the envelope layout and the fragment encoding correctly before your first share works. Each SDK does that part, so the call you write takes plaintext fields and hands back a finished link:

const share = await crs.shares.create({
  title: 'Staging deploy credentials',
  fields: [{ key: 'Password', value: 'correct horse', type: 'password' }],
})

share.link // https://crs.sh/aB3dEf12#1xK9...

If you are working in one of these four languages, this is the path we would rather you took. Client-side encryption remains the reference for anyone implementing the wire format from scratch.

Installing

LanguagePackageInstall
Node@credenshare/sdk on npmnpm install @credenshare/sdk
Pythoncredenshare on PyPIpip install credenshare
Gogithub.com/CredenShare/credenshare-sdk-gogo get github.com/CredenShare/credenshare-sdk-go
Rustcredenshare on crates.iocargo add credenshare

All four are published, and each repository is tagged and carries a GitHub Release at the same version. The commands above are unpinned on purpose — the registry resolves the current release, and a 0.x line moves often enough that a version written into documentation is stale before you read it. Pin in your own manifest, not from here.

These are 0.x releases. The surface is free to change at any minor bump, and it has: recent releases altered the Field type in two languages and split one error class into three. Read the changelog in the repository before upgrading, and pin a version you have tested.

What every client does

  • Encrypts before sending. A fresh 32-byte content key per share, AES-256-GCM under a key derived with HKDF. The content key never goes to CredenShare.
  • Assembles the link, including the fragment that carries the key. That link is the secret.
  • Derives the access token from the content key, so the server can gate a read without being able to decrypt.
  • Sends an Idempotency-Key on every create.
  • Verifies webhook signatures, including during the 24-hour rotation window when deliveries carry two.
  • Parses the credential, and derives the custody public key from it. Each client exposes a Credential type over the three-part crs_sk_live_<keyId>.<authSecret>[.<custodySecret>] form, and can derive the custody public key locally — the value you register so an API-created share can be re-read later.
  • Refuses to transmit the custody secret. The third part never reaches the wire. The bearer value is assembled from the parsed parts rather than by trimming the string, and asserted again at the request boundary.
  • Raises a dedicated error on a 429, exposing Retry-After as seconds. Node reads both forms the header can take — delta-seconds and an HTTP-date converted to whole seconds from now. Python, Go and Rust parse digits only, so an HTTP-date leaves the value unset there. None of them sleep or retry on a 429 for you.
  • Wraps the content key for account custody, on request. Node, Python and Go take a custody flag on create: the client wraps the content key to the custody public key derived from your credential's third part, so the share stays readable from your dashboard and not only from its link. Rust does not offer it yet — a Rust-created share is link-only.
  • Ships the conformance vectors inside the installed artifact, so you can check the exact build you installed. See Conformance vectors.

What none of them do

This list is exhaustive as of today, and worth reading before you plan around a capability.

  • No reads. readLink, read_link and ReadLink exist and always fail. The recipient path is guarded by proof-of-work and captcha checks that bearer auth would skip, so exposing it to a credential would turn the API into an enumeration bypass. Open the link in a browser.
  • No credential or webhook management. Nothing mints, rotates, lists or revokes an API key or a signing secret, and nothing manages a webhook endpoint. Rotation is only ever consumed, by passing several secrets to verify.
  • No typed webhook events. There is no constructEvent-style parse-and-verify helper, no event-type constants, no delivery listing and no replay. You verify the raw body, then parse it yourself. The event list is the reference.
  • No MCP. See MCP — it is the only programmatic route to secure requests and browser-assisted shares.
  • Shares only. All four speak /shares. Pastes, secure requests, files, teams, organizations, seats, subscriptions and audit logs are not covered.

Choosing between them

They implement the same specification and interoperate — content one writes, another reads. The differences that would actually change your choice:

NodePythonGoRust
Runtime floorNode 20Python 3.9Go 1.21Rust 1.88
Runtime dependenciesnonecryptography, httpxnone (stdlib)RustCrypto, serde, base64, ureq
Also runs onDeno, Bun, Workers, browsers
Asynchronousyesnono (context-aware)no
Walks every page for youiterateAlliter_allIterateSharesfor_each_share
Bounded — the walk cannot loop foreveryesyesyesyes
Testing seaminjectable fetchhttpx transport*http.Clientnone
Extra field members preservedyesyesyesyes
Short code cannot escape the pathyesyesyesyes
Rejects a malformed fragmentmostlyyesyesyes
Crypto compiles without the HTTP stackn/a — no HTTP dependencynon/a — stdlibdefault-features = false
Custody wrap on createyesyesyesno

The one remaining no is a capability Rust has not implemented, not a bug.

Every client's page-walking helper now refuses a response that echoes a page number other than the one requested, because a server that does that makes progress unobservable. Node, Python and Rust additionally stop at a hard ceiling of 100,000 pages; Go stops on the first short page or the reported total instead, and carries no absolute cap.

The five defects that used to sit in that table are fixed: Go and Rust preserve extra field members, Python percent-encodes the short code and Rust refuses one that is not opaque, and Python's fragment decode validates the alphabet. None of them ever affected the cryptography — every client still reproduces the conformance vectors exactly. The one remaining no is a capability Rust has not implemented, not a bug.

The fragment row is still a spectrum rather than a pass/fail: Node accepts + and / — not base64url characters — which the other three reject. Only Go, Python and Rust reject strictly.

The specification is what binds them

The four SDKs and the CredenShare application share no code. That is deliberate: a package the production application depended on would be a supply-chain surface, and for a product whose claim is that we cannot read your data, it is the wrong surface to open.

The cost of that decision is drift, and drift here does not produce a test failure — it produces content that can never be decrypted. What holds the implementations together is the specification plus a fixture every one of them must reproduce, byte for byte. If a client and the specification disagree, the client is wrong.


All four clients work on every plan, free included. Create an account to mint an API key, or talk to us about volume and team seats.