Sentroy

Sentroy Client SDK

Official TypeScript SDK for the Sentroy business mail & storage platform.
Send transactional and bulk email, manage domains and mailboxes, run an inbox, store and serve media — from one typed client.

npm version npm downloads license

Documentation  ·  Mail  ·  Storage  ·  React components  ·  Status

--- ## What's in the box - **Mail** — verified domains, mailboxes, multi-language templates, IMAP-backed inbox, transactional and bulk send, suppressions, webhooks, audience lists, deliverability logs. - **Storage** — isolated buckets, multipart uploads, image and media transformations, signed download URLs. - **Env Vault** — runtime env variable management (`@sentroy-co/client-sdk/vault`) — change a value in the dashboard, your app picks it up on the next read; no rebuild. - **React drop-ins** — ``, `` and `` / `useEnv()` (`@sentroy-co/client-sdk/react` + `@sentroy-co/client-sdk/vault/react`). - **One client, two backends** — point at `https://sentroy.com` for the hosted platform, or your own deployment for self-hosted. Same API, same types. ## Install ```bash npm install @sentroy-co/client-sdk ``` ## First request ```ts import { Sentroy } from "@sentroy-co/client-sdk" const sentroy = new Sentroy({ baseUrl: "https://sentroy.com", // or your self-hosted URL companySlug: "my-company", accessToken: "stk_...", // Dashboard → Admin → Access Tokens }) // Send your first transactional email await sentroy.send.email({ from: "noreply@yourdomain.com", to: ["customer@example.com"], subject: "Welcome to Acme", html: "

Glad you're here.

", }) ``` ## Upload a file ```ts const file = new File([blob], "invoice.pdf", { type: "application/pdf" }) const media = await sentroy.media.upload({ bucketSlug: "invoices", file, }) console.log(media.url) // signed URL, served from the CDN ``` That's the smallest useful surface. Every other resource (`domains`, `mailboxes`, `templates`, `inbox`, `audience`, `webhooks`, `suppressions`, `logs`, `buckets`, `media`) follows the same `sentroy..(...)` shape with full TypeScript types. ## React: CropDialog A full-screen, iOS Photos-style image crop dialog built on [`react-mobile-cropper`](https://advanced-cropper.github.io/react-mobile-cropper/) (which sits on top of [`react-advanced-cropper`](https://advanced-cropper.github.io/react-advanced-cropper/)). Lazy subpath — only imported when you reference it. **1. Add the stylesheet once** (root layout / `_app` / global CSS entry — anywhere it loads on every page that may open the dialog): ```ts import "@sentroy-co/client-sdk/react/crop/styles.css" ``` We ship `react-mobile-cropper`'s baseline `style.css`, no extra theme. If you'd rather use the desktop-flavored variants (`compact` / `bubble` / `classic` / `corners` from advanced-cropper, or the mobile baseline directly), see [advanced-cropper themes](https://advanced-cropper.github.io/react-advanced-cropper/docs/guides/themes) and import the package CSS yourself instead of ours. **2. Open the dialog with a `File`:** ```tsx "use client" import { useState } from "react" import dynamic from "next/dynamic" const CropDialog = dynamic( () => import("@sentroy-co/client-sdk/react/crop").then((m) => m.CropDialog), { ssr: false }, ) export function UploadButton() { const [file, setFile] = useState(null) return ( <> setFile(e.target.files?.[0] ?? null)} /> {file && ( { setFile(null) if (out) uploadCroppedFile(out) // Apply → cropped File // out === null → Cancel; out === file → Use original }} /> )} ) } ``` The dialog returns a `File` (cropped or original), `null` on cancel. Aspect presets, rotate (`R` / `Shift+R`), flip, zoom and a live preview are built in. ## Env Vault Manage your env vars in the dashboard at [vault.sentroy.com](https://vault.sentroy.com), bootstrap your deploy with one token, and read values via a typed helper — no rebuild on change. ```ts // server side import { getEnv, getEnvOrThrow, getEnvWithFallback, preloadEnv } from "@sentroy-co/client-sdk/vault" await preloadEnv() // optional fail-fast at boot const dbUrl = await getEnv("DATABASE_URL") const turnstile = await getEnvOrThrow("BETTER_AUTH_TURNSTILE_SECRET") // Migration helper — vault'tan oku, yoksa process.env fallback. // Sentroy app'lerini kademeli olarak migrate ederken kullanışlı. const stripe = await getEnvWithFallback("STRIPE_SECRET_KEY") ``` ```tsx // React: SSR-injected provider + hook (no FOUC) import { getPublicEnvs } from "@sentroy-co/client-sdk/vault" import { EnvProvider, useEnv } from "@sentroy-co/client-sdk/vault/react" // app/layout.tsx (server) const envs = await getPublicEnvs() return {children} // any "use client" component const siteKey = useEnv("TURNSTILE_SITE_KEY") ``` Bootstrap is a single env: `SENTROY_ENV_API_KEY`. Public/private split is enforced server-side — the React hook only ever sees `public: true` variables. Full reference at [docs.sentroy.com/env-vault](https://docs.sentroy.com/env-vault). ### Webhooks (real-time invalidation) Skip the 5-min cache TTL — point the vault at your app and it'll POST whenever any variable changes. The default handler verifies the HMAC-SHA256 signature and refreshes the cache: ```ts // app/api/sentroy/vault-webhook/route.ts import { createVaultWebhookHandler } from "@sentroy-co/client-sdk/vault" export const POST = createVaultWebhookHandler({ secret: process.env.SENTROY_VAULT_WEBHOOK_SECRET!, }) ``` Configure the receiver URL in the vault dashboard under the project's **Webhooks** tab; the secret comes back once at create-time. Provide your own `onChange` handler for custom logic. ### CLI The package ships a `sentroy` CLI with four command groups: `env`, `mail`, `storage`, `ai`. Full reference at [docs.sentroy.com/cli](https://docs.sentroy.com/cli). ```bash # Env Vault sync (SENTROY_ENV_API_KEY) npx sentroy env push .env.production --delete-missing npx sentroy env pull .env.staging --force # Mail / Storage queries (SENTROY_API_KEY + SENTROY_COMPANY_SLUG) npx sentroy mail templates list npx sentroy mail logs list --status=bounced --days=7 npx sentroy storage buckets list npx sentroy storage media list --type=image npx sentroy mail templates list --output=json | jq '.[].name' # Install the Sentroy AI Skill into your project (Claude, Cursor, Windsurf, # AGENTS.md). Lets AI agents use Sentroy without trial-and-error. npx sentroy ai install ``` The vault token's (project, environment) scope is implicit. Mail/storage commands need `SENTROY_API_KEY` (`stk_<48-hex>`) plus a company slug (env var or `--company-slug`). Every list/get supports `--output=json` for scripting. Full command list and recipes: [docs.sentroy.com/cli](https://docs.sentroy.com/cli). ### React Native / Expo The SDK runs in React Native / Expo with one extra subpath for platform-specific helpers: [`@sentroy-co/client-sdk/auth/react-native`](https://docs.sentroy.com/auth-projects#react-native). ```ts import AsyncStorage from "@react-native-async-storage/async-storage" import * as WebBrowser from "expo-web-browser" import { SentroyAuth } from "@sentroy-co/client-sdk/auth" import { createAsyncStorageAdapter, openSocialAuthSession, } from "@sentroy-co/client-sdk/auth/react-native" export const auth = new SentroyAuth({ projectSlug: "acme", apiKey: process.env.EXPO_PUBLIC_SENTROY_AUTH_KEY!, storage: createAsyncStorageAdapter(AsyncStorage, { projectSlug: "acme" }), }) // Social login via the system browser, with a deep-link callback. const tokens = await openSocialAuthSession(WebBrowser, { authorizeUrl: auth.socialAuthorizeUrl("google", { redirectUri: "myapp://auth/callback" }), redirectUri: "myapp://auth/callback", }) if (tokens) await auth.setSession(tokens) ``` Notes: passkeys are web-only, `SentroyAuthAdmin` is server-only (do not import in Expo bundles), and `media.upload` from `expo-document-picker` accepts `{uri, name, type}` as `body`. Full guide: [docs.sentroy.com/auth-projects#react-native](https://docs.sentroy.com/auth-projects#react-native). ### AI Skill Sentroy ships a canonical [`SKILL.md`](https://docs.sentroy.com/skill.md) (Anthropic Skills format) so AI coding agents (Claude Code, Cursor, Windsurf, OpenAI Codex via AGENTS.md) understand the auth model, endpoints, and gotchas without trial-and-error. ```bash npx sentroy ai install # autodetects target tools and installs everywhere ``` Targets: `.claude/skills/sentroy/SKILL.md`, `.cursor/rules/sentroy.mdc`, `.windsurfrules`, and `AGENTS.md` (sentinel-block merged). See [docs.sentroy.com/ai-skills](https://docs.sentroy.com/ai-skills) for the full install guide. ## Self-hosted vs hosted The SDK is identical in both modes. Only `baseUrl` changes: | Mode | `baseUrl` | |---|---| | Sentroy Cloud (hosted) | `https://sentroy.com` | | Self-hosted | `https://your-sentroy-host` | Pick the deployment that fits your compliance, latency and cost requirements. Migrate either direction without changing application code. ## Documentation Full reference, interactive examples, and multi-language code samples (TypeScript, Go, Python, PHP, cURL) live at: **[docs.sentroy.com](https://docs.sentroy.com)** Sections: [Quickstart](https://docs.sentroy.com) · [Mail](https://docs.sentroy.com/mail) · [Storage](https://docs.sentroy.com/storage) · [React](https://docs.sentroy.com/react) · [Tools](https://docs.sentroy.com/tools) ## Requirements - Node.js 18+ (uses native `fetch`) - React 18+ (only if you import from `/react`) - Tailwind CSS in the host app (only for React components) ## For AI agents A single-file, comprehensive reference covering every endpoint, parameter and response shape lives at [`AGENTS.md`](AGENTS.md). Drop the raw URL into a context window: ``` https://raw.githubusercontent.com/Sentroy-Co/client-sdk/refs/heads/main/typescript/AGENTS.md ``` ## License [MIT](LICENSE)