@vennyx/soliagile-sdk
v0.1.0
Published
Typed TypeScript client for the SoliAgile REST API (teams, issues, workflow states, labels, comments, projects) — tenant-scoped API key auth, cursor pagination iterators.
Downloads
47
Readme
@vennyx/soliagile-sdk
Typed TypeScript client for the SoliAgile REST API — teams, issues,
workflow states (board columns), labels, comments, and projects. Zero runtime dependencies,
built on native fetch (Node 18+, Node 24+ needs no polyfill).
Install
npm install @vennyx/soliagile-sdkAuthentication
SoliAgile uses tenant-scoped API keys for programmatic access. Create one from your tenant settings (owner/admin role, requires a Business plan or above):
POST /api/v1/tenants/:id/api-keys
Authorization: Bearer <your Zitadel JWT>
Content-Type: application/json
{ "name": "CI pipeline" }The response includes a plaintextKey field that starts with sa_ — this is shown only
once. Store it securely (e.g. as a SOLIAGILE_API_KEY secret); the server only ever keeps a
hash of it.
Usage
import { SoliAgileClient } from '@vennyx/soliagile-sdk';
const client = new SoliAgileClient({
apiKey: process.env.SOLIAGILE_API_KEY!,
// baseUrl defaults to https://api.soliagile.com/api/v1 — override for
// self-hosted deployments:
// baseUrl: 'https://api.your-domain.com/api/v1',
});
// Fetch a single page.
const { items, hasNextPage, endCursor } = await client.issues.list({
teamId: 'team-id',
stateType: 'started',
first: 20,
});
// Or iterate every page transparently with an async generator.
for await (const issue of client.issues.iterate({ teamId: 'team-id' })) {
console.log(issue.identifier, issue.title);
}
// Create / update / move issues.
const issue = await client.issues.create({ teamId: 'team-id', title: 'Fix login bug' });
await client.issues.update(issue.id, { priority: 1 });
await client.issues.move(issue.id, { workflowStateId: 'done-state-id' });
// Teams, workflow states, labels, comments, projects.
const teams = await client.teams.list();
const board = await client.issues.board(teams.items[0]!.id);
await client.comments.create(issue.id, 'Looking into this now.');
// Who am I / which tenants can this key see?
const me = await client.me.get();Cursor pagination
Every list endpoint returns a CursorPage<T> ({ items, endCursor, hasNextPage }). Each
resource also exposes an iterate() method that wraps the exported paginate() helper and
walks every page for you:
import { paginate } from '@vennyx/soliagile-sdk';
for await (const team of paginate((q) => client.teams.list(q), { q: 'eng' })) {
console.log(team.key);
}Error handling
All non-2xx responses throw a typed subclass of SoliAgileApiError:
import { SoliAgileAuthError, SoliAgileForbiddenError, SoliAgileNotFoundError, SoliAgileRateLimitError, SoliAgileValidationError } from '@vennyx/soliagile-sdk';
try {
await client.issues.get('does-not-exist');
} catch (error) {
if (error instanceof SoliAgileNotFoundError) {
// 404
} else if (error instanceof SoliAgileAuthError) {
// 401 — invalid or revoked API key
} else if (error instanceof SoliAgileForbiddenError) {
// 403 — e.g. the tenant's plan no longer includes API access
} else if (error instanceof SoliAgileRateLimitError) {
console.log('retry after (ms):', error.retryAfterMs);
} else if (error instanceof SoliAgileValidationError) {
console.log(error.errors);
}
throw error;
}Custom fetch
The client uses the global fetch by default. Inject your own implementation (useful for
testing, or on Node <18):
const client = new SoliAgileClient({
apiKey: process.env.SOLIAGILE_API_KEY!,
fetch: myFetchImplementation,
});Resources
| Resource | Methods |
| ------------------------ | ------------------------------------------------------------------------ |
| client.teams | list, iterate, get, create, update, archive |
| client.workflowStates | list, create, update, reorder, delete |
| client.issues | list, iterate, get, create, update, move, archive, board |
| client.labels | list, iterate, get, create, update, delete, addToIssue, removeFromIssue |
| client.comments | list, iterate, create, update, delete |
| client.projects | list, iterate, get, getProgress, create, update, delete |
| client.me | get |
See @vennyx/soliagile-mcp if you want to expose these
resources as MCP tools to an AI agent (Claude, Codex, etc.) instead of calling the SDK directly.
License
MIT
