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 https://api.majikscale.com/api/v1/partner/connectors \
-H "Authorization: Bearer sk_live_..."await fetch("https://api.majikscale.com/api/v1/partner/connectors", {
method: "GET",
headers: {
Authorization: "Bearer sk_live_...",
},
});{
"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 -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"}]}}'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" },
],
},
}),
});{
"detail": "Core as a service is not available for this company"
}{
"detail": "Invalid key"
}POST/api/v1/partner/searches
Starts the same search the product runs. The body is a query, and an optional webhook URL. You get a session id and a status. A stored lead spends one plan credit. A failed search does not spend a search. This path ignores the Core as a service price.
curl -X POST https://api.majikscale.com/api/v1/partner/searches \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"query":"warehouse ledger in the public record"}'await fetch("https://api.majikscale.com/api/v1/partner/searches", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_...",
"Content-Type": "application/json",
},
body: JSON.stringify({ query: "warehouse ledger in the public record" }),
});{
"session_id": "11111111-1111-4111-8111-111111111111",
"status": "processing"
}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 -X GET https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111 \
-H "Authorization: Bearer sk_live_..."await fetch("https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111", {
method: "GET",
headers: {
Authorization: "Bearer sk_live_...",
},
});{
"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 -X GET https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111/leads \
-H "Authorization: Bearer sk_live_..."await fetch("https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111/leads", {
method: "GET",
headers: {
Authorization: "Bearer sk_live_...",
},
});{
"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": []
}
]
}POST/api/v1/partner/searches/{session_id}/close
Closes the session and returns the session id with status closed. A later read of the leads has name, email, and phone set to null, and linkedin_url empty.
curl -X POST https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111/close \
-H "Authorization: Bearer sk_live_..."await fetch("https://api.majikscale.com/api/v1/partner/searches/11111111-1111-4111-8111-111111111111/close", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_...",
},
});{
"session_id": "11111111-1111-4111-8111-111111111111",
"status": "closed"
}{
"session_id": "11111111-1111-4111-8111-111111111111",
"status": "closed",
"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": null,
"email": null,
"phone": null,
"linkedin_url": "",
"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.
{
"lead_id": "22222222-2222-4222-8222-222222222222",
"session_id": "11111111-1111-4111-8111-111111111111",
"type": "lead_stored"
}{
"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 -X GET https://api.majikscale.com/api/v1/partner/connectors \
-H "Authorization: Bearer sk_live_..."await fetch("https://api.majikscale.com/api/v1/partner/connectors", {
method: "GET",
headers: {
Authorization: "Bearer sk_live_...",
},
});{
"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 -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"}]}}'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 -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"}}'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" },
}),
});{
"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
}{
"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 -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"}}'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" },
}),
});{
"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
}{
"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 -X GET https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333 \
-H "Authorization: Bearer sk_live_..."await fetch("https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333", {
method: "GET",
headers: {
Authorization: "Bearer sk_live_...",
},
});{
"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 -X POST https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333/close \
-H "Authorization: Bearer sk_live_..."await fetch("https://api.majikscale.com/api/v1/partner/jobs/33333333-3333-4333-8333-333333333333/close", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_...",
},
});{
"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"
}