Quickstart: your first API call in 5 minutes

Create a key, test it, create a lead, list your leads and subscribe to a webhook. You only need a terminal (or any HTTP tool) and a SpaceKru account on a paid plan or its free trial.

The SpaceKru API (v1.1) is a REST/JSON API available on every paid SpaceKru plan. It syncs leads both ways (upsert by external_id), adds leads to campaigns, creates and moves deals and asks AI Employees to follow up, manages products, quotes, orders, payments and bookings, lets your platform chat with your Customer Service AI Employee, and sends signed webhooks for 16 events that say who caused each change. Base URL: https://app.spacekru.com/api/public/v1. Authentication: Bearer API key (sk_live_…). Documentation: https://www.spacekru.com/developers (Spanish: https://www.spacekru.com/es/developers). OpenAPI 3.1: https://app.spacekru.com/api/public/v1/openapi.json.

Leer en español

1. Create an API key

  1. Open the panel. In SpaceKru, go to Integrations → API & Webhooks.
  2. Create the key. Click Create key, name it after the tool that will use it (for example "Quickstart" or "Zapier") and choose Read & write.
  3. Copy it now. The key (sk_live_…) is shown once. Copy it and keep it in a password manager or your server's secrets. If you lose it, revoke it and create a new one.

Then make it available to your terminal as an environment variable — never paste a key into code you commit:

macOS / Linux
export SPACEKRU_API_KEY="sk_live_your_key_here"
Windows (PowerShell)
$env:SPACEKRU_API_KEY = "sk_live_your_key_here"

2. Test the key

GET /ping tells you which account the key belongs to, its plan and the key's scopes.

curl
curl "https://app.spacekru.com/api/public/v1/ping" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/ping', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/ping",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Response 200
{
  "object": "ping",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "name": "Acme Corp",
  "plan": "Business",
  "scopes": [
    "read",
    "write"
  ]
}

3. Create a lead

Send at least one way to contact the person (an email, a phone or a social profile). external_id is the id of this person in YOUR system (optional). The Idempotency-Key header makes the request safe to retry: if it is sent twice, only one lead is created.

curl
curl -X POST "https://app.spacekru.com/api/public/v1/leads" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: typeform-resp-8f2a1c" \
  -d '{
  "full_name": "Maria Lopez",
  "work_email": "maria.lopez@example.com",
  "work_phone": "+13055550142",
  "company_name": "Acme Corp",
  "job_title": "Operations Manager",
  "city": "Miami",
  "country": "United States",
  "tags": [
    "typeform",
    "spring-promo"
  ],
  "external_id": "crm-88412",
  "initial_note": "Asked for a demo from the spring promo form."
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/leads', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'typeform-resp-8f2a1c',
  },
  body: JSON.stringify({
    "full_name": "Maria Lopez",
    "work_email": "maria.lopez@example.com",
    "work_phone": "+13055550142",
    "company_name": "Acme Corp",
    "job_title": "Operations Manager",
    "city": "Miami",
    "country": "United States",
    "tags": [
      "typeform",
      "spring-promo"
    ],
    "external_id": "crm-88412",
    "initial_note": "Asked for a demo from the spring promo form."
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/leads",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
        "Idempotency-Key": "typeform-resp-8f2a1c",
    },
    json={
        "full_name": "Maria Lopez",
        "work_email": "maria.lopez@example.com",
        "work_phone": "+13055550142",
        "company_name": "Acme Corp",
        "job_title": "Operations Manager",
        "city": "Miami",
        "country": "United States",
        "tags": ["typeform", "spring-promo"],
        "external_id": "crm-88412",
        "initial_note": "Asked for a demo from the spring promo form.",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Response 201
{
  "object": "lead",
  "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "type": "person",
  "full_name": "Maria Lopez",
  "business_name": null,
  "job_title": "Operations Manager",
  "work_email": "maria.lopez@example.com",
  "personal_email": null,
  "work_phone": "+13055550142",
  "personal_phone": null,
  "company_name": "Acme Corp",
  "city": "Miami",
  "country": "United States",
  "status": "new",
  "source": "api",
  "tags": [
    "typeform",
    "spring-promo"
  ],
  "instagram_profile": null,
  "linkedin_profile_url": null,
  "website": null,
  "external_id": "crm-88412",
  "created_at": "2026-10-19T14:32:10.000Z",
  "updated_at": "2026-10-19T14:32:10.000Z"
}

Run it a second time with a different Idempotency-Key: SpaceKru recognizes the same email and answers 409 DUPLICATE_RESOURCE with the existing_id of the lead — no duplicate. More in Idempotency & duplicates.

4. List your leads

curl
curl "https://app.spacekru.com/api/public/v1/leads?limit=5" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/leads?limit=5', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/leads?limit=5",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)

Newest first. When has_more is true, pass next_cursor as cursor to get the next page (up to 100 per page). See Pagination & sync.

5. Get notified of new leads

Webhooks push events to a URL of yours. You need a public https:// URL that answers 200 — for a first test, a Zapier Catch Hook URL or your own server works. Then subscribe it once:

curl
curl -X POST "https://app.spacekru.com/api/public/v1/subscriptions" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "event_type": "lead.created",
  "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/"
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/subscriptions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "event_type": "lead.created",
    "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/"
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/subscriptions",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    json={
        "event_type": "lead.created",
        "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Response 201
{
  "object": "subscription",
  "id": "0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d",
  "event_type": "lead.created",
  "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/",
  "is_active": true,
  "failure_count": 0,
  "disabled_reason": null,
  "last_success_at": null,
  "created_at": "2026-10-19T14:40:00.000Z",
  "exclude_own_changes": false,
  "secret": "whsec_EXAMPLE0nlyN0tARealSecretDoNotUseIt00000"
}

Now create another lead (step 3, with a new email and a new Idempotency-Key): within seconds your URL receives a lead.created event. Your subscription also appears in Integrations → API & Webhooks, where you can remove it.

What's next

  • Two-way sync: Keep your platform and SpaceKru identical, without loops.
  • Webhooks: All 16 events, signatures, retries and delivery guarantees.
  • API reference: Every endpoint, field and error, with samples.