Files
keysat-client-rust/README.md
T
Keysat 5dd301cd69 v0.2.0 — policy_slug on start_purchase + list_public_policies
Mirrors the TS SDK 0.2.0 changes (cf c3a57a0 in keysat-client-ts) so
all four language clients have parity on the tiered-purchase surface.

Breaking change on start_purchase: positional `(buyer_email,
redirect_url)` args replaced with a `&StartPurchaseOptions` struct.
Migration is mechanical:

  // before
  client.start_purchase(slug, None, None).await?;
  // after
  client.start_purchase(slug, &Default::default()).await?;

  // tier-aware
  client.start_purchase(slug, &StartPurchaseOptions {
      policy_slug: Some("pro"),
      buyer_email: Some("buyer@example.com"),
      ..Default::default()
  }).await?;

The struct has fields for buyer_email, buyer_note, redirect_url,
code, and the new policy_slug. New `list_public_policies` method
fetches the buyer-visible tier list (no auth) so an in-app tier
picker can render dynamically.

Lib + tests build clean; the example's anyhow-not-in-deps issue is
pre-existing and unrelated.
2026-05-09 09:08:39 -05:00

77 lines
2.2 KiB
Markdown

# licensing-client
Rust client for [`Keysat`](https://github.com/keysat-xyz/keysat) — a self-hosted Bitcoin-paid software licensing server that runs on Start9.
## What you get
- **Offline verification**: check a license key with just the issuing server's public key. No network. Default feature.
- **Online validation**: live revocation check and fingerprint binding via the service's `/v1/validate` endpoint. Optional.
- **Purchase flow**: kick off a BTCPay checkout and poll for the issued key. Optional.
## Install
```toml
[dependencies]
licensing-client = "0.1"
# Or, with the online features:
licensing-client = { version = "0.1", features = ["online"] }
```
## 5-line offline check
```rust
use licensing_client::{Verifier, PublicKeyPem};
let pubkey = PublicKeyPem::from_str(include_str!("issuer.pub"))?;
let verifier = Verifier::new(pubkey);
let ok = verifier.verify(&key_from_user)?;
println!("licensed for product {}", ok.product_id);
```
That's the whole integration. `include_str!("issuer.pub")` embeds your public key at build time; if the verifier says OK, the key is real and was issued by you.
## 10-line online check (with revocation + fingerprint)
```rust
use licensing_client::online::Client;
let client = Client::new("https://license.example.com")?;
let result = client
.validate(&key_from_user, Some("my-product"), Some(&machine_fingerprint))
.await?;
if !result.ok {
eprintln!("rejected: {:?}", result.reason);
std::process::exit(1);
}
```
The server enforces revocation live and does trust-on-first-use fingerprint binding, so the same key used from a second machine gets rejected.
## Purchase flow
```rust
use licensing_client::StartPurchaseOptions;
// Default tier:
let session = client.start_purchase("my-product", &Default::default()).await?;
// Specific tier (e.g. Pro):
let session = client.start_purchase("my-product", &StartPurchaseOptions {
policy_slug: Some("pro"),
buyer_email: Some("buyer@example.com"),
..Default::default()
}).await?;
// open session.checkout_url in the user's browser
loop {
let poll = client.poll_purchase(&session.invoice_id).await?;
if let Some(key) = poll.license_key { break key; }
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
```
## License
MIT OR Apache-2.0.