Developers

Havadis MCP server, REST API and Node SDK

One API key, two doors: MCP-capable AI clients, and @havadis/sdk for your own backend.

Endpoint
https://api.gethavadis.co/api/mcp
Protocol
mcp/streamable-http

Quickstart

  1. 1

    Sign in or sign up

    Havadis uses Google or email login. The next step needs a logged-in dashboard session.

  2. 2

    Mint an API key

    From Dashboard → Settings → Developer, create a key. The plaintext is shown only once — copy it now.

  3. 3

    Configure your client

    Pick your MCP client below and paste the snippet into the right config file. Set the key as a Bearer token.

  4. 4

    Verify the connection

    Before invoking any tool, run a `tools/list` ping to make sure the server is reachable with your key.

  5. 5

    Call your first tool

    Once `tools/list` works, invoke a tool with `tools/call`. See the Tool reference for input schemas.

Connect your client

Copy-paste configurations for common MCP clients. Each tab shows the snippet, the exact file path, and a restart hint.

claude_desktop_config.json
{
  "mcpServers": {
    "havadis": {
      "type": "http",
      "url": "https://api.gethavadis.co/api/mcp",
      "headers": {
        "Authorization": "Bearer havadis_<your-key-here>"
      }
    }
  }
}

Restart: Quit and reopen Claude Desktop after saving the config.

Verify the connection

Run a `tools/list` request before invoking any tool — it confirms the endpoint is reachable and your Bearer token is valid.

bash
curl -X POST 'https://api.gethavadis.co/api/mcp' \
  -H 'Authorization: Bearer havadis_<your-key-here>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Expected response (truncated)
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "create_brand",
        "description": "...",
        "inputSchema": { "type": "object", "properties": { ... } }
      }
    ]
  }
}

If the response isn't 200 OK

ResponseCauseFix
401 UnauthorizedThe token is missing, malformed or revoked.Create a new key in the dashboard.
404 / connection refusedThe endpoint URL is wrong.It must end with `/mcp` — no trailing slash.
429 Too Many RequestsYou hit the request limit.Wait `retryAfterMs` and retry (see Request limits).

Tool reference

All tools are rendered from the live manifest — a newly added tool appears here within 5 minutes.

No tools

Rate limits

Applied per workspace (1 active key = 1 workspace). Scales with plan; Pro and Pro+ allow higher request volume.

REST API & @havadis/sdk

Production from code: feed your blog with Havadis content, queue jobs from cron, pull content in a static-site build.

Install
npm install @havadis/sdk
Quick start (Node, server-side)
import { Havadis } from '@havadis/sdk';

const havadis = new Havadis({ apiKey: process.env.HAVADIS_API_KEY! });
const [brand] = await havadis.brands.list();

const job = await havadis.brand(brand.id).jobs.createAndWait({
  contentTypes: ['blog'],
  brief: '...',
});
  • Credit-spending calls require an Idempotency-Key; the SDK generates one per call, and retries replay the same result — no double charges.
  • Errors use a closed envelope with frozen codes; match the code, not the text. 429 responses tell you how long to wait via retry_after_seconds.
  • The key stays server-side: the package's browser condition and a runtime guard deliberately break any build that would ship it to visitors.
MethodPathSummary
GET/api/v1/meIdentity, effective scopes and limits of the calling key
GET/api/v1/creditsCredit pool snapshot of the workspace owner's account
GET/api/v1/brandsBrands owned by the calling tenant
GET/api/v1/brands/{brandId}One owned brand
GET/api/v1/brands/{brandId}/contentsKeyset-paged contents, drafts included
GET/api/v1/brands/{brandId}/contents/{idOrSlug}Full content (body + SEO/AEO/GEO), ETag/If-None-Match aware
POST/api/v1/brands/{brandId}/contents/{contentId}/publishPublish to the customer's own site (custom_website)
POST/api/v1/brands/{brandId}/contents/{contentId}/unpublishTake content off the custom_website channel
POST/api/v1/brands/{brandId}/contents/{contentId}/site-publicationReport where your site published a post Havadis sent it, or that it holds it
POST/api/v1/brands/{brandId}/jobsQueue a content generation job (async — poll jobs.get)
GET/api/v1/brands/{brandId}/jobsKeyset-paged jobs
POST/api/v1/brands/{brandId}/jobs/cost-previewFree per-model cost preview for a job shape
GET/api/v1/brands/{brandId}/jobs/{jobId}One job with per-platform state
POST/api/v1/brands/{brandId}/topics/suggestQueue topic discovery (async — results land in topics.list)
GET/api/v1/brands/{brandId}/topics/runs/{runId}One discovery run: its status, the error code if it failed, and its suggestions
GET/api/v1/brands/{brandId}/topicsTopic suggestions for the brand

Connect your website

Show Havadis posts on your own site. Havadis knows where each post lives and measures its performance from the day it goes live.

  1. 1

    Connect the site

    In Dashboard → Settings → Connected Accounts → Custom Website, enter your site's name and domain. Leave the webhook address empty.

  2. 2

    Read the posts

    In the browser, use the keyless public feed; it serves published posts only. On your server, @havadis/sdk also reads drafts.

  3. 3

    Serve each post under its slug

    Show posts under one path plus the feed's slug, for example /blog/{slug}. That is how Havadis knows each post's address. A site that picks its own paths reports them through the site-publication endpoint.

  4. 4

    Add a webhook if you need one

    If pages must refresh the moment a post is published, serve POST /api/webhooks/havadis on your domain; Havadis sends there by default. Events are signed with Standard Webhooks; the signing secret is shown once when you connect the site, and rotating it on the connection issues a new one. A site that reads the feed on every request needs no webhook.

MethodPathSummary
GET/api/v1/public/brands/{brandId}/contentsPublished posts, no key (an array; ?format=paged for an envelope)
GET/api/v1/public/brands/{brandId}/contents/{slugOrId}One post, by slug or id
GET/api/v1/public/brands/{brandId}/contents/{slugOrId}/coverCover image; embed it directly as an image on your site

Your cookie preferences

We use cookies to keep your session secure and improve your experience. You decide which non-essential ones we may use. Cookie Policy