@elvenvtt/api
v0.7.2
Published
Typed REST client for the Elven creator API. The shared core consumed by @elvenvtt/cli, @elvenvtt/mcp-account, and any third-party tooling.
Downloads
104
Maintainers
Readme
@elvenvtt/api
Typed REST client for the Elven creator API. Zero runtime dependencies — works in Node, Bun, Deno, browsers, and edge runtimes (Workers, Vercel Edge).
Full docs: docs.elvenvtt.com/docs/agent-platform
npm install @elvenvtt/apiimport { createClient } from '@elvenvtt/api';
const elven = createClient();
await elven.setTokens({ accessToken: process.env.ELVEN_TOKEN!, kind: 'pat' });
const me = await elven.whoami();
const mine = await elven.listings.mine();This is the shared core that powers @elvenvtt/cli and @elvenvtt/mcp-account. Use it directly when you want to script Elven from your own code without the CLI binary or MCP server.
What's in the client
All methods are typed; full types ship in dist/index.d.ts.
elven.whoami() // → { userId, email, slug, claims }
elven.setTokens({ accessToken, kind })
elven.logout()
elven.listings.create(input)
elven.listings.list({ type, search, ... })
elven.listings.mine()
elven.listings.get(idOrSlug)
elven.listings.update(id, input)
elven.listings.delete(id)
elven.publish.uploadFile({ listingId, slug, path, content })
elven.publish.manifestUrl(listingId, slug) // utility — builds the public URL
elven.posts.create({ title, bodyText, status, visibility })
elven.posts.get(id)
elven.posts.byUser(userId)
elven.posts.update(id, input)
elven.posts.delete(id)
elven.drops.create({ name, openAt, closeAt, eligibility, claimContents })
elven.drops.get(id)
elven.drops.byUser(userId)
elven.drops.update(id, input)
elven.drops.delete(id)
elven.drops.claim(id)
elven.drops.feed() // open drops from creators you follow
elven.drops.claims() // drops you've claimed
elven.followers.count(userId)
elven.followers.following()
elven.followers.state(creatorIds) // map: creatorId → bool
elven.followers.follow({ creatorSlug })
elven.followers.unfollow(creatorId)
elven.analytics.overview() // dashboard (one round-trip)
elven.analytics.sales() // seller sales rollup
elven.tokens.create({ label, expiresInDays })
elven.tokens.list()
elven.tokens.revoke(id)Tokens & refresh
The client takes a TokenStore (default: in-memory). Pass your own to persist across processes.
import { createClient, type TokenStore } from '@elvenvtt/api';
const myStore: TokenStore = {
async read(profile = 'default') { /* ... */ },
async write(tokens, profile = 'default') { /* ... */ },
async clear(profile = 'default') { /* ... */ },
};
const elven = createClient({ tokenStore: myStore });Two credential kinds:
- JWT session (
kind: 'jwt') — short-lived (~1 hour), auto-refreshed when there's less than 60s of life left. Rotated tokens are written back to the store automatically. This is whatelven loginobtains through the browser OAuth flow. - Personal access token (
kind: 'pat') — long-lived opaque token starting withel_pat_. No refresh. Generate from the Elven Studio (Developer → CLI Tokens) or viaelven tokens create.
Errors
The client maps server responses to four classes — catch by instanceof:
| Class | When | Suggested handling |
|---|---|---|
| AuthError | 401/403, no token, refresh failed | Prompt re-login. CLI exit code 60. |
| ApiError | 4xx/5xx with a JSON body | Show e.status + e.body. CLI exit code 70. |
| UsageError | Client-side: missing required input | Fix the call site. CLI exit code 80. |
| NetworkError | fetch() threw (DNS, offline, etc.) | Retry / surface. CLI exit code 90. |
All four extend ElvenError, which extends Error.
import { AuthError, ApiError } from '@elvenvtt/api';
try {
await elven.listings.create({ ... });
} catch (e) {
if (e instanceof AuthError) return promptLogin();
if (e instanceof ApiError && e.status === 422) return showValidationErrors(e.body);
throw e;
}Public contract: /v1/*
The client only calls /v1/* endpoints on the Elven backend. These paths are locked — additive changes only, no breaking shape changes within a major version. The unversioned aliases (/api/listings, /posts, etc.) still exist for the SvelteKit web app but aren't part of the public contract.
The base URLs default to production and can be overridden for local dev / staging:
createClient({
stripeUrl: 'https://stripe.example.com',
syncUrl: 'https://sync.example.com',
uploadUrl: 'https://api.example.com',
});Security
Tokens passed to setTokens() are long-lived credentials. Store them via the TokenStore interface (the CLI uses keytar; your code can use any secure backing store) and never log them. Audit + revoke at Studio Developer → CLI Tokens. Full guidance at docs.elvenvtt.com/docs/agent-platform/security.
License
MIT.
