Skip to content
majikscale

API reference

Partner calls use https://api.majikscale.com. The same paths are on http://localhost:8000 when you run core locally. Lead search spends plan credits. Core as a service uses the price set for that company.

AuthAuthorization: Bearer sk_...

Send the company secret on every call. A missing, revoked, or non-company key returns 401. The public id pk_... does not authenticate. A company admin creates the key in product settings. The secret and the webhook signing secret are shown once.

curl
curl https://api.majikscale.com/api/v1/partner/connectors \
  -H "Authorization: Bearer sk_live_..."
fetch
await fetch("https://api.majikscale.com/api/v1/partner/connectors", {
  method: "GET",
  headers: {
    Authorization: "Bearer sk_live_...",
  },
});
Response · 401
{
  "detail": "Invalid key"
}

Errors401 and 403

FastAPI errors are an object with detail. A missing, revoked, or malformed key returns 401 with the same detail. A job that is not built-in lead_search returns 403 when Core as a service is not available for that company. Another company’s job id returns 404.

curl
curl -X POST https://api.majikscale.com/api/v1/partner/jobs \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"connector":"records","question":"volume by channel","input":{"records":[{"amount":40,"created_at":"2026-03-01","channel":"web"},{"amount":10,"created_at":"2026-03-02","channel":"web"},{"amount":10,"created_at":"2026-03-02","channel":"desk"}]}}'
fetch
await fetch("https://api.majikscale.com/api/v1/partner/jobs", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  connector: "records",
  question: "volume by channel",
  input: {
    records: [
      { amount: 40, created_at: "2026-03-01", channel: "web" },
      { amount: 10, created_at: "2026-03-02", channel: "web" },
      { amount: 10, created_at: "2026-03-02", channel: "desk" },
    ],
  },
}),
});
Response · 403
{
  "detail": "Core as a service is not available for this company"
}
Response · 401
{
  "detail": "Invalid key"
}

GET/api/v1/partner/searches/{session_id}

Returns the session id, status, stage, discovered domains, and lead ids. It does not include names or email addresses.

curl
curl -X GET https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111 \
  -H "Authorization: Bearer sk_live_..."
fetch
await fetch("https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111", {
  method: "GET",
  headers: {
    Authorization: "Bearer sk_live_...",
  },
});
Response
{
  "session_id": "11111111-1111-4111-8111-111111111111",
  "status": "completed",
  "stage": "finding_companies",
  "domains": ["harbor-ledger.example"],
  "lead_ids": ["22222222-2222-4222-8222-222222222222"]
}

GET/api/v1/partner/searches/{session_id}/leads

Returns the session id, status, and leads. While the session is open, each lead includes name, email, phone, and linkedin_url. Those personal fields are removed when the session is closed. Role, company, industry, and location stay.

curl
curl -X GET https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111/leads \
  -H "Authorization: Bearer sk_live_..."
fetch
await fetch("https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111/leads", {
  method: "GET",
  headers: {
    Authorization: "Bearer sk_live_...",
  },
});
Response
{
  "session_id": "11111111-1111-4111-8111-111111111111",
  "status": "completed",
  "leads": [
    {
      "id": "22222222-2222-4222-8222-222222222222",
      "session_id": "11111111-1111-4111-8111-111111111111",
      "company": "Harbor Ledger",
      "domain": "harbor-ledger.example",
      "position": "Warehouse lead",
      "industry": "Logistics",
      "location": "Lagos",
      "name": "Sample Person",
      "email": "sample@harbor-ledger.example",
      "phone": "+2348000000001",
      "linkedin_url": "https://www.linkedin.com/in/sample-person",
      "verification_status": null,
      "confidence": 0,
      "score": 0,
      "signals": [],
      "community_url": null,
      "social_url": null,
      "lead_tags": []
    }
  ]
}

POSTYour webhook URL

If the company key has a webhook URL, majikscale POSTs lead_stored and search_finished after the database commit. The signed body has type and session_id, plus lead_id when a lead was stored. It does not include a name, email, or phone. The header is X-Majik-Signature: sha256=..., an HMAC-SHA256 of the raw body with the webhook signing secret. A failed delivery does not fail the search.

Response · lead_stored
{
  "lead_id": "22222222-2222-4222-8222-222222222222",
  "session_id": "11111111-1111-4111-8111-111111111111",
  "type": "lead_stored"
}
Response · search_finished
{
  "session_id": "11111111-1111-4111-8111-111111111111",
  "type": "search_finished"
}

GET/api/v1/partner/connectors

Lists enabled connectors. Each item is a slug and a name. Disabled connectors and upstream URLs are not included.

curl
curl -X GET https://api.majikscale.com/api/v1/partner/connectors \
  -H "Authorization: Bearer sk_live_..."
fetch
await fetch("https://api.majikscale.com/api/v1/partner/connectors", {
  method: "GET",
  headers: {
    Authorization: "Bearer sk_live_...",
  },
});
Response
{
  "connectors": [
    { "slug": "lead_search", "name": "Lead search" },
    { "slug": "records", "name": "Records" }
  ]
}

POST/api/v1/partner/jobs

Preferred input is input.records, an array of flat JSON objects. Include an amount field and an ISO date or time field when you want volume over time. Category fields such as type, channel, status, or currency are useful. Do not send names, emails, phones, account numbers, customer ids, or card numbers. Those are ignored and never stored.

Also accepted: input.url or input.upload_url, an https URL you host that returns the same JSON, either { "records": [] } or a top-level array. Rows are not stored. Recommendations appear only when the dataset supports an optimization. Analysis runs on Core and is available to a company with an active Core as a service price.

curl
curl -X POST https://api.majikscale.com/api/v1/partner/jobs \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"connector":"records","question":"volume by channel","input":{"records":[{"amount":40,"created_at":"2026-03-01","channel":"web"},{"amount":10,"created_at":"2026-03-02","channel":"web"},{"amount":10,"created_at":"2026-03-02","channel":"desk"}]}}'
fetch
await fetch("https://api.majikscale.com/api/v1/partner/jobs", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  connector: "records",
  question: "volume by channel",
  input: {
    records: [
      { amount: 40, created_at: "2026-03-01", channel: "web" },
      { amount: 10, created_at: "2026-03-02", channel: "web" },
      { amount: 10, created_at: "2026-03-02", channel: "desk" },
    ],
  },
}),
});
curl · URL
curl -X POST https://api.majikscale.com/api/v1/partner/jobs \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"connector":"records","question":"volume by channel","input":{"url":"https://files.example.com/dataset.json"}}'
fetch · URL
await fetch("https://api.majikscale.com/api/v1/partner/jobs", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  connector: "records",
  question: "volume by channel",
  input: { url: "https://files.example.com/dataset.json" },
}),
});
Response
{
  "id": "33333333-3333-4333-8333-333333333333",
  "connector": "records",
  "status": "completed",
  "question": "volume by channel",
  "session_id": null,
  "result": {
    "understanding": [
      "Read 3 rows.",
      "Summed amount.",
      "Time runs from 2026-03-01 to 2026-03-02.",
      "Used channel."
    ],
    "patterns": [
      "Volume by day peaks on 2026-03-01 at 40.",
      "Volume falls from 40 in 2026-03-01 to 20 in 2026-03-02.",
      "channel web is 83% of volume.",
      "The question mentions channel."
    ],
    "recommendations": [
      "Review the peak period 2026-03-01, which holds the most volume.",
      "Review 2026-03-01, which holds more volume than 2026-03-02.",
      "channel web accounts for most of the volume."
    ],
    "fields_used": ["amount", "channel", "created_at"],
    "fields_ignored": []
  },
  "created_at": "2026-10-11T12:00:00",
  "closed_at": null
}
Response · 403
{
  "detail": "Core as a service is not available for this company"
}

POST/api/v1/partner/jobs

Any connector other than built-in lead search needs an active Core as a service price. With no upstream, the result is the question and the tokens from the text you sent. An upstream connector stores the JSON that service returned. A failed upstream call is status failed and is not charged. If Core as a service is not available, the call is 403.

curl
curl -X POST https://api.majikscale.com/api/v1/partner/jobs \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"connector":"your-connector","question":"warehouse ledger","input":{"text":"public warehouse ledger"}}'
fetch
await fetch("https://api.majikscale.com/api/v1/partner/jobs", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  connector: "your-connector",
  question: "warehouse ledger",
  input: { text: "public warehouse ledger" },
}),
});
Response
{
  "id": "33333333-3333-4333-8333-333333333333",
  "connector": "your-connector",
  "status": "completed",
  "question": "warehouse ledger",
  "session_id": null,
  "result": {
    "question": "warehouse ledger",
    "tokens": ["public", "warehouse", "ledger"]
  },
  "created_at": "2026-10-11T12:00:00",
  "closed_at": null
}
Response · 403
{
  "detail": "Core as a service is not available for this company"
}

GET/api/v1/partner/jobs/{job_id}

Returns the job id, connector, status, question, session id when the job is a search, the result, and the timestamps. A records result has patterns, recommendations, and field names. Raw rows are not stored.

curl
curl -X GET https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333 \
  -H "Authorization: Bearer sk_live_..."
fetch
await fetch("https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333", {
  method: "GET",
  headers: {
    Authorization: "Bearer sk_live_...",
  },
});
Response
{
  "id": "33333333-3333-4333-8333-333333333333",
  "connector": "records",
  "status": "completed",
  "question": "volume by channel",
  "session_id": null,
  "result": {
    "understanding": [
      "Read 3 rows.",
      "Summed amount.",
      "Time runs from 2026-03-01 to 2026-03-02.",
      "Used channel."
    ],
    "patterns": [
      "Volume by day peaks on 2026-03-01 at 40.",
      "Volume falls from 40 in 2026-03-01 to 20 in 2026-03-02.",
      "channel web is 83% of volume.",
      "The question mentions channel."
    ],
    "recommendations": [
      "Review the peak period 2026-03-01, which holds the most volume.",
      "Review 2026-03-01, which holds more volume than 2026-03-02.",
      "channel web accounts for most of the volume."
    ],
    "fields_used": ["amount", "channel", "created_at"],
    "fields_ignored": []
  },
  "created_at": "2026-10-11T12:00:00",
  "closed_at": null
}

POST/api/v1/partner/jobs/{job_id}/close

Closes the job and returns the same job shape with status closed.

curl
curl -X POST https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333/close \
  -H "Authorization: Bearer sk_live_..."
fetch
await fetch("https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333/close", {
  method: "POST",
  headers: {
    Authorization: "Bearer sk_live_...",
  },
});
Response
{
  "id": "33333333-3333-4333-8333-333333333333",
  "connector": "records",
  "status": "closed",
  "question": "volume by channel",
  "session_id": null,
  "result": {
    "understanding": [
      "Read 3 rows.",
      "Summed amount.",
      "Time runs from 2026-03-01 to 2026-03-02.",
      "Used channel."
    ],
    "patterns": [
      "Volume by day peaks on 2026-03-01 at 40.",
      "Volume falls from 40 in 2026-03-01 to 20 in 2026-03-02.",
      "channel web is 83% of volume.",
      "The question mentions channel."
    ],
    "recommendations": [
      "Review the peak period 2026-03-01, which holds the most volume.",
      "Review 2026-03-01, which holds more volume than 2026-03-02.",
      "channel web accounts for most of the volume."
    ],
    "fields_used": ["amount", "channel", "created_at"],
    "fields_ignored": []
  },
  "created_at": "2026-10-11T12:00:00",
  "closed_at": "2026-10-11T12:05:00"
}