Build on GrowthOS
A real, small API today — 4 documented endpoints, real Bearer-key auth, real rate limits, a working SDK and CLI. We'd rather ship an honest, growing surface than a docs site describing features that don't exist.
4 real endpoints, documented in full
Base URL: https://growthos.kvlbusinesssolutions.com — Bearer-token auth on every call.
/api/v1/workflows/{workflowId}/triggerworkflows:triggerTriggers a workflow run.
curl -X POST "https://growthos.kvlbusinesssolutions.com/api/v1/workflows/{workflowId}/trigger" \
-H "Authorization: Bearer YOUR_API_KEY"/api/export/companiesexport:companies:readExports your organization's companies (format=csv|crm|excel|pdf).
curl "https://growthos.kvlbusinesssolutions.com/api/export/companies?format=csv" \
-H "Authorization: Bearer YOUR_API_KEY"/api/export/dealsexport:deals:readExports your organization's deals (format=csv|crm|excel|pdf).
curl "https://growthos.kvlbusinesssolutions.com/api/export/deals?format=csv" \
-H "Authorization: Bearer YOUR_API_KEY"/api/export/contactsexport:contacts:readExports your organization's contacts (format=csv|crm|excel|pdf).
curl "https://growthos.kvlbusinesssolutions.com/api/export/contacts?format=csv" \
-H "Authorization: Bearer YOUR_API_KEY"A real, minimal GraphQL endpoint
One query, one mutation today — the same real auth and business logic as the REST API, exposed through GraphQL. Not yet a full schema.
type Query {
apiKeyInfo: ApiKeyInfo
}
type Mutation {
triggerWorkflow(workflowId: String!): TriggerResult
}
type ApiKeyInfo {
organizationId: String!
scopes: [String!]!
rateLimitPerHour: Int!
}
type TriggerResult {
runId: String!
}curl -X POST "https://growthos.kvlbusinesssolutions.com/api/graphql" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ apiKeyInfo { organizationId scopes rateLimitPerHour } }"}'Auth failures return GraphQL's own error envelope ({ errors: [...] }), not the REST API's { error } shape.
Real client libraries, honestly scoped
Two real, hand-written SDKs today — not yet published to a package registry, but genuinely functional. The rest are on our roadmap, not faked.
A real, working client covering all 4 endpoints, usable in Node.js or the browser.
Copy the client from our docs — not yet published to npm
A real, working client covering all 4 endpoints.
Copy the client from our docs — not yet published to PyPI
Not built yet.
Not built yet.
Not built yet.
Not built yet.
Not built yet.
A real command-line client
Every command below genuinely works against the live API — not a mockup.
git clone <this repo>
cd growthos
node cli/kvl.js --helpkvl auth <apiKey> [--base-url <url>]Save your API key locally.kvl workflows:trigger <workflowId>Trigger a real workflow run.kvl export:companies [--format csv|crm|excel|pdf]Export your companies to a local file.kvl export:deals [--format csv|excel|pdf]Export your deals to a local file.kvl export:contacts [--format csv|excel|pdf]Export your contacts to a local file.kvl --helpList real commands.How authentication actually works
Real methods only — no SSO/SAML claims that aren't true yet.
API Keys (Bearer)
Bcrypt-hashed, scoped, per-key rate limit — the real authentication method for the public API.
OAuth 2.0 (Sign-in)
Google, Microsoft, GitHub, and LinkedIn — for signing into the product, not for public API access.
Webhook Signing
HMAC-SHA256 signatures on every outbound webhook, so you can verify authenticity.
Enterprise SSO / SAML
Not built yet — see our Trust Center for the current honest status.
Real HMAC-signed webhook delivery
Every webhook we send is signed, with automatic retry on failure. There's no fixed catalog of event types yet — webhooks are configured per Automation Builder workflow, not a platform-wide event bus.
import crypto from "crypto";
function verifySignature(secret, rawBody, signatureHeader) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}Every outbound webhook request carries a signature header computed the same way — configure webhook steps from the Automation Builder in your dashboard.
Real limits, not a live quota dashboard yet
Every API key is rate-limited by a real, Redis-backed sliding window — here's exactly how it works.
Default limit
1,000 requests / hour, per API key
Window
Rolling 1-hour window
Configurable
Per-key limit can be set at creation
Exceeded response
429 { "error": "Rate limit exceeded." }
On a 429, back off and retry — the response body always tells you exactly what happened: { "error": "Rate limit exceeded." }. A live, per-key quota-remaining view is on our roadmap, not built yet.
Error reference
Every real error shape the API returns, verbatim.
{ "error": "Invalid or missing API key." }Check your Authorization header is exactly `Bearer YOUR_API_KEY`.
{ "error": "This API key does not have the '<scope>' scope." }Generate a new key with the required scope from API settings.
{ "error": "Rate limit exceeded." }Back off and retry after your rolling 1-hour window resets.
Real, downloadable resources
OpenAPI Specification
A real, valid OpenAPI 3.0 spec for every documented endpoint.
Postman Collection
Import directly into Postman — Bearer auth pre-configured.
CLI Tool
A real command-line client covering all 4 endpoints. Not published to npm yet — clone the repo and run it locally.
See CLI docs below
No public community yet — but we want to hear from you
We don't have a Discord, Slack community, or public forum today. Rather than link somewhere that doesn't exist, tell us directly.
Talk to us directly
Questions, feedback, or interested in an early developer community when we launch one? Reach out.
Put your growth engine on autopilot
Start qualifying, engaging, and converting pipeline with AI agents today. No credit card required, and your first workflow can be live in under fifteen minutes.