@cannasage/sdk
v0.1.0-beta.1
Published
Official JavaScript/TypeScript SDK for the CannaSage Developer API.
Downloads
26
Maintainers
Readme
@cannasage/sdk
Official JavaScript/TypeScript SDK for the CannaSage Developer API. Cannabis cultivation data, SOPs, grow projects, environmental sensors, and data connectors — typed, async-friendly, Node 18+ / modern browsers.
Beta. This SDK is pre-1.0 and may change. Pin a specific version in production.
Install
npm install @cannasage/sdk
# or
pnpm add @cannasage/sdk
# or
yarn add @cannasage/sdkQuick start
API key (server-to-server)
import { CannaSageClient } from '@cannasage/sdk';
const cs = new CannaSageClient({ apiKey: process.env.CANNASAGE_API_KEY });
const { data: sops } = await cs.sops.list({ category: 'ipm' });
console.log(sops);Create an API key from the CannaSage dashboard under Settings → Developer. Keys are shown once on creation — store them securely.
Bearer JWT (short-lived programmatic access)
const cs = new CannaSageClient({ bearerToken: userJwt });OAuth 2.0 client credentials
const cs = new CannaSageClient({
clientId: process.env.CANNASAGE_CLIENT_ID,
clientSecret: process.env.CANNASAGE_CLIENT_SECRET,
scopes: ['read', 'connectors'],
});
// The SDK exchanges credentials for an access token lazily on the first
// request and caches it until ~1 minute before expiry.
await cs.connectors.list();Resources
| Resource | Methods |
|----------|---------|
| sops | list(params), get(id) |
| projects | list(params), get(id) |
| connectors | list(), get(id), create(params), update(id, params), delete(id), sync(id), devices(id), data(id, params), pushData(id, params) |
| environmental | listData(params) |
| insights | list(params) |
| growTracking | costs(params), harvests(params) |
| webhooks | listEvents(), list(), create(params), update(id, params), delete(id), listDeliveries(id), test(id, event), redeliver(id, deliveryId) |
| oauth | list(), create(params), delete(id) |
| keys | list(), create(params), revoke(id), rotate(id), forceRevoke(id), setRateLimit(id, limit), usage(id, params) |
Webhooks
Verify incoming webhook requests by validating the X-CannaSage-Signature header against the raw request body:
import { verifyWebhookSignature } from '@cannasage/sdk';
app.post('/webhooks/cannasage', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.header('X-CannaSage-Signature') ?? '';
const isValid = verifyWebhookSignature(req.body, signature, process.env.CANNASAGE_WEBHOOK_SECRET!);
if (!isValid) return res.status(401).end();
const event = JSON.parse(req.body.toString());
// ... handle event
res.sendStatus(204);
});The helper uses constant-time comparison and never throws on mismatch — it returns boolean.
Error handling
All HTTP errors throw CannaSageAPIError with a stable code, status, and requestId:
import { CannaSageAPIError } from '@cannasage/sdk';
try {
await cs.sops.get('missing');
} catch (err) {
if (err instanceof CannaSageAPIError) {
console.error(err.code, err.status, err.message);
if (err.code === 'NOT_FOUND') { /* ... */ }
}
}Rate limits, retries, timeouts
- Retries: the SDK retries up to 3 times on
429(rate limited) and503(overloaded), respecting theRetry-Afterheader with a 30s cap. Exponential backoff otherwise. - Timeout: default 30s per request. Override globally via
new CannaSageClient({ timeoutMs: 60_000 }). - Idempotency:
POSTrequests automatically receive anIdempotency-Keyheader (auto-UUID). Pass{ idempotencyKey: 'your-key' }per request to override or{ idempotencyKey: false }to disable.
Configuration reference
new CannaSageClient({
apiKey: 'csk_live_...', // or bearerToken, or clientId + clientSecret
baseUrl: 'https://cannasage.app', // override for local dev / staging
timeoutMs: 30_000,
maxRetries: 3,
});TypeScript
All methods return Promise<ApiResponse<T>> where ApiResponse<T> = { data: T; meta?: Record<string, unknown> }. Resource types (SOP, Project, Connector, …) are exported from the package root.
License
MIT — see LICENSE.
