Two query endpoints — blocking and streaming. Both accept plain-English questions and return sourced answers. Use blocking for simple integrations, streaming for real-time UI.
POST/v1/query
Ask a question. Returns a complete answer with citations in a single response. Set timeout=30 on your HTTP client — complex queries over large document sets can take up to 10 seconds.
Request body
Field
Type
Required
Default
Description
question
string
Yes
—
The question to ask in plain English
filters
object
No
{}
Metadata key-value pairs to scope the search (AND logic)
top_k
integer
No
6
Number of document chunks retrieved before ranking (1–20)
Request
python
import httpx
response = httpx.post(
"https://api.usejack.io/v1/query",
headers={"Authorization": "Bearer jack_xxxxxxxx"},
json={
"question": "What is the remote work policy?",
"filters": {"department": "HR"}
},
timeout=30
)
data = response.json()
print(data["answer"])
print(data["citations"])
bash
curl -X POST https://api.usejack.io/v1/query \
-H "Authorization: Bearer jack_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"question": "What is the remote work policy?", "filters": {"department": "HR"}}'
javascript
const res = await fetch("https://api.usejack.io/v1/query", {
method: "POST",
headers: {
"Authorization": "Bearer jack_xxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
question: "What is the remote work policy?",
filters: { department: "HR" },
}),
});
const data = await res.json();
console.log(data.answer);
console.log(data.citations);
Response
json
{
"answer": "Employees may work remotely up to 3 days per week with manager approval. Remote work requests must be submitted at least 48 hours in advance via the HR portal.",
"citations": [
{
"text": "...employees are permitted to work remotely up to 3 days per week with prior manager approval. Requests must be submitted 48 hours in advance...",
"source": "remote-work-policy.pdf",
"score": 0.94
}
],
"org_id": "your-org-id"
}
Filtering examples
python
# Scope to one department
{"question": "What is the leave policy?", "filters": {"department": "HR"}}
# Scope to one document type
{"question": "Find termination clauses", "filters": {"document_type": "contract"}}
# Scope to one client
{"question": "What are the payment terms?", "filters": {"client_id": "CLIENT-001"}}
# Multiple filters — AND logic
{"question": "...", "filters": {"department": "legal", "year": "2024"}}
# No filter — searches all documents in your org
{"question": "Summarise our refund policy"}
If the answer is not in your documents, jack says so — it never fabricates. The citations array will be empty in that case.
POST/v1/query/stream
Same as /v1/query but streams the answer token by token via Server-Sent Events. Citations arrive as a final SSE event before [DONE]. Use this for a typing effect in your UI.
Request
Same body as /v1/query.
python
import httpx, json
with httpx.stream(
"POST",
"https://api.usejack.io/v1/query/stream",
headers={"Authorization": "Bearer jack_xxxxxxxx"},
json={
"question": "What is the remote work policy?",
"filters": {"department": "HR"}
},
timeout=60
) as response:
citations = []
for line in response.iter_lines():
if line.startswith("data: "):
payload = line[6:]
if payload == "[DONE]":
break
event = json.loads(payload)
if "token" in event:
print(event["token"], end="", flush=True)
elif "citations" in event:
citations = event["citations"]
elif "error" in event:
print("Error:", event["error"])
print() # newline after streamed answer
print("Sources:", citations)
javascript
const response = await fetch("https://api.usejack.io/v1/query/stream", {
method: "POST",
headers: {
"Authorization": "Bearer jack_xxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ question: "What is the remote work policy?" }),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const lines = decoder.decode(value).split("\n");
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
const payload = line.slice(6);
if (payload === "[DONE]") break;
const event = JSON.parse(payload);
if (event.token) process.stdout.write(event.token);
if (event.citations) console.log("\nSources:", event.citations);
}
}