Sign up a customer

Silky's signup endpoint is public - no auth, no demo, no sales call. You give it an email. It gives you back an account plus a trial API key that is live immediately.

Endpoint

POST /api/v1/accounts/signup

Body: { "email": "founder@acme.com", "source": "claude-agent" }

Response (HTTP 202):

{
  "success": true,
  "data": {
    "account_id": "acc_01HXXX...",
    "status": "pending_verification",
    "trial_api_key": "sk_trial_abc123...",
    "email_verified": false,
    "message": "Check your email to verify your address. Your API key is active now - you can start building immediately.",
    "enrichment_task_id": "task_01HXXX..."
  },
  "meta": { "request_id": "req_abc123def456" },
  "error": null
}

The trial_api_key is returned once. Store it; you cannot retrieve it later. Generate a new one via POST /api/v1/api-keys if lost.

curl

curl -X POST https://app.silky.so/api/v1/accounts/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "founder@acme.com", "source": "claude-agent"}'

JavaScript

const res = await fetch('https://app.silky.so/api/v1/accounts/signup', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: 'founder@acme.com', source: 'claude-agent' }),
});
const { data } = await res.json();
const apiKey = data.trial_api_key;
// Store apiKey. All subsequent calls use: Authorization: Bearer <apiKey>

Python

import requests

r = requests.post(
    'https://app.silky.so/api/v1/accounts/signup',
    json={'email': 'founder@acme.com', 'source': 'claude-agent'},
    timeout=30,
)
r.raise_for_status()
api_key = r.json()['data']['trial_api_key']
# Store api_key. Use it as Authorization: Bearer <api_key> on every subsequent call.

What happens next

  1. A verification email goes to the address. The customer clicks it once to unlock the full plan; the trial key keeps working regardless.
  2. Silky runs an async enrichment task (enrichment_task_id) that crawls the domain, fetches branding colours + logo, and sets a sensible timezone. Poll GET /api/v1/tasks/{id} if you want to wait for it.
  3. An account_enriched webhook fires when enrichment finishes (about 10-30 seconds). Subscribe via POST /api/v1/webhooks if you want push instead of poll.

Duplicate handling

If the email already has an account, the endpoint returns HTTP 202 with the existing account_id and a message telling the caller to check email for the verification link. It does not return a new API key. Build your flow so a duplicate signup is a no-op, not an error.

If another account already claims the same email domain (e.g. someone at acme.com signed up before), the endpoint returns HTTP 409 with error.type = "conflict" and a human-readable reason. Bounce the user to that account's admin or pick a different domain.

Verifying the email programmatically

The verification link in the email points to /auth/verify-email?token=.... For a fully headless onboarding flow, you cannot read the email on behalf of the user. Two options:

  • Let the human click the link themselves. The trial key works in the meantime.
  • Use the invite flow instead: have an existing admin call POST /api/v1/accounts/{id}/users to create a member with a known password. That skips email verification entirely but requires you to already be signed in.

Rate limits

The signup endpoint is IP-rate-limited. Steady state you can create one account per minute per IP. Burst up to 10 in 10 minutes. If you hit 429, wait for the Retry-After header and try again.

Hand this to Claude

Sign up a new Silky account for founder@acme.com, store the trial
API key in an env var called SILKY_API_KEY, and print the account_id.