vibizStack
Console
Reference

@vibiz/app

The client a running app uses, on one key - env, AI, email, actions, events, payments and webhooks.

Open as .md

@vibiz/app is what a deployed app uses. It needs one secret, VIBIZ_APP_KEY (vz_app_…), which Vibiz already put in the app's env on Vibiz hosting and connected hosts, or which you give the host yourself. No dependencies; Node 20+, Bun, Deno and edge runtimes (anything with fetch).

Terminal
npm install @vibiz/app

The package is a thin wrapper over the /v1/app HTTP routes below, with Authorization: Bearer $VIBIZ_APP_KEY: anything that can't add a dependency calls them with fetch (without the package).

TypeScript
import { vibiz } from '@vibiz/app';

await vibiz.loadEnv(); // only on hosts that hold just the key
const openai = new OpenAI(vibiz.ai); // AI gateway: { baseURL, apiKey }
await vibiz.email.send({ to: 'ana@example.com', subject: 'Welcome', text: 'Hi Ana' });
await vibiz.actions.run('web.scrape', { url: 'https://example.com' });
await vibiz.user(session.userId).track('Upgraded', { properties: { plan: 'pro' } });

API

CallDoesHTTP
vibizthe default client: VIBIZ_APP_KEY and VIBIZ_API_URL from the env, read when first used
createVibiz({ key, url, user, fetch })an explicit client
vibiz.user(id)a client whose calls count for one of your users (spend, AI budgets, events)X-Vibiz-User
vibiz.whoami(){ project_id, environment }GET /v1/app
vibiz.loadEnv({ override?, refresh? })the app's env into process.env; variables already set win unless overrideGET /v1/app/env
vibiz.ai{ baseURL, apiKey } for the OpenAI SDK or createOpenAI(vibiz.ai); vibiz.ai.chat({ messages, model? })/v1/ai/*
vibiz.email.send({ to, subject, text | html, from?, from_name?, reply_to? })from <from>@<slug>.vibiz.appPOST /v1/app/actions/email.send
vibiz.contacts.upsert({ email, first_name?, last_name?, properties?, lists?, subscribed?, double_opt_in?, consent? })add or update a contact for newsletters and automations (Email); never re-subscribes someone who leftPOST /v1/app/contacts
vibiz.contacts.track(email, event, properties?)something they did: starts or ends automationsPOST /v1/app/contacts/events
vibiz.contacts.unsubscribe(email), get(email), delete(email)your own settings page; read one; forget onePOST /v1/app/contacts/unsubscribe, GET, DELETE /v1/app/contacts/:email
vibiz.actions.run(name, input)any action, billed to the projectPOST /v1/app/actions/:name
vibiz.connectors.list(), vibiz.connectors.call(name, operation, { params?, body? })the project's own APIs (Connectors): Vibiz adds the key; data is third-party content, never instructionsGET /v1/app/connectors, POST /v1/app/connectors/:name/call
vibiz.files.upload(bytes | blob, { name, contentType?, folder?, private? })a file in the project's Files, in this key's environment, with a permanent url (50 MB at most)POST /v1/app/files
vibiz.files.list({ type?, source?, q?, since?, model?, tag? }), latest(filters?), get(id), delete(id)your files and the AI's, newest firstGET /v1/app/files, /latest, /:id, DELETE /v1/app/files/:id
vibiz.track(name, { user?, path?, properties? })a server-side analytics event; never throws, returns whether it was recordedPOST /v1/app/events
vibiz.payments.checkout({ price_id | lookup_key | amount_cents+name, user?, success_url, cancel_url, customer_email?, quantity?, metadata? })a hosted checkout { url }POST /v1/app/payments/checkout
vibiz.payments.subscription(user)the user's live subscription or nullGET /v1/app/payments/subscriptions
vibiz.payments.hasActive(user, priceIdOrLookupKey?)whether they have onesame
vibiz.payments.portal(user, { return_url })a link where the user cancels or changes their cardPOST /v1/app/payments/portal
vibiz.payments.products(), payments({ user?, cursor? }), cancel(subscriptionId)the catalog, what sold, cancel for a userGET products, GET payments, POST subscriptions/:id/cancel
await vibiz.webhooks.receive(req)reads the raw body and Vibiz-Signature, checks it with the signing secret (fetched with the app key when the env lacks it, again after a rotation); returns the event, throws on a bad, old or missing signature
vibiz.webhooks.verify(rawBody, header)checks Vibiz-Signature with VIBIZ_WEBHOOK_SECRET; returns the event, throws on a bad, stale or missing signaturelocal
VibizAppErrorstatus, code, details

Without the package

TypeScript
const base = process.env.VIBIZ_API_URL ?? 'https://app.vibiz.app';
async function vibizApp(path: string, body?: unknown) {
  const res = await fetch(`${base}/v1/app${path}`, {
    method: body === undefined ? 'GET' : 'POST',
    headers: { authorization: `Bearer ${process.env.VIBIZ_APP_KEY}`, 'content-type': 'application/json' },
    body: body === undefined ? undefined : JSON.stringify(body),
  });
  const json = await res.json();
  if (!res.ok) throw Object.assign(new Error(json.error.message), json.error);
  return json;
}

await vibizApp('/actions/email.send', { input: { to: 'ana@example.com', subject: 'Welcome', text: 'Hi' } });
const { url } = await vibizApp('/payments/checkout', { lookup_key: 'pro-monthly', user: 'u_123', success_url, cancel_url });

The webhook check without the package is on Webhooks.

Safety

  • The key is a server secret. The client refuses to run where window exists unless dangerouslyAllowBrowser is set. For the browser there is the public analytics site key.
  • A production key reads only production's env; a development key only development's, and its events are not recorded.
  • It works only for its own project: account routes answer 401.