Ask
curl --request POST \
--url https://api.userepo.com/v1/ask \
--header 'Content-Type: application/json' \
--data '
{
"query": "<string>",
"limit": 123
}
'import requests
url = "https://api.userepo.com/v1/ask"
payload = {
"query": "<string>",
"limit": 123
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({query: '<string>', limit: 123})
};
fetch('https://api.userepo.com/v1/ask', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.userepo.com/v1/ask",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => '<string>',
'limit' => 123
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.userepo.com/v1/ask"
payload := strings.NewReader("{\n \"query\": \"<string>\",\n \"limit\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.userepo.com/v1/ask")
.header("Content-Type", "application/json")
.body("{\n \"query\": \"<string>\",\n \"limit\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.userepo.com/v1/ask")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"query\": \"<string>\",\n \"limit\": 123\n}"
response = http.request(request)
puts response.read_body{
"question": "<string>",
"answer": "<string>",
"citations": [
{}
],
"context": [
{}
]
}Reference
Ask
Grounded answer generation with citations. Repo retrieves context and asks the LLM for you.
POST
/
v1
/
ask
Ask
curl --request POST \
--url https://api.userepo.com/v1/ask \
--header 'Content-Type: application/json' \
--data '
{
"query": "<string>",
"limit": 123
}
'import requests
url = "https://api.userepo.com/v1/ask"
payload = {
"query": "<string>",
"limit": 123
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({query: '<string>', limit: 123})
};
fetch('https://api.userepo.com/v1/ask', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.userepo.com/v1/ask",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => '<string>',
'limit' => 123
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.userepo.com/v1/ask"
payload := strings.NewReader("{\n \"query\": \"<string>\",\n \"limit\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.userepo.com/v1/ask")
.header("Content-Type", "application/json")
.body("{\n \"query\": \"<string>\",\n \"limit\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.userepo.com/v1/ask")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"query\": \"<string>\",\n \"limit\": 123\n}"
response = http.request(request)
puts response.read_body{
"question": "<string>",
"answer": "<string>",
"citations": [
{}
],
"context": [
{}
]
}/v1/ask is the highest-level endpoint: retrieve context + generate an answer + return citations in one round-trip. Use it when you want the simplest possible integration. Use /v1/context if you want to bring your own prompt or LLM.
Required action
ask
Cost
1 credit per call. Note:/v1/ask also incurs OpenAI completion costs (passed through transparently — credits cover both retrieval and the generation token cost in your tier’s bundle).
Body
Same as/v1/search:
string
required
The user-facing question.
integer
default:"8"
How many context hits to feed the LLM. Min 1, max 25.
Response
{
"question": "What did we decide about the brand color?",
"answer": "Based on Repo memory, the strongest context is:\n[1] Brand decisions: We're keeping the lime-green accent because Q2 testing showed...\n[2] Design review notes: The team agreed to retire the navy variant...",
"citations": [
{ "index": 1, "sourceItemId": "uuid", "title": "Brand decisions" },
{ "index": 2, "sourceItemId": "uuid", "title": "Design review notes" }
],
"context": [
{
"sourceItemId": "uuid",
"title": "Brand decisions",
"content": "We're keeping the lime-green accent...",
"url": "https://www.notion.so/...",
"provider": "notion",
"score": 0.8432
}
]
}
string
Echo of the input query.
string
LLM-generated answer, cited inline as
[N]. When OpenAI is unavailable Repo falls back to a deterministic synthesis from the top hits.array
The retrieved hits the LLM saw. Includes provider, URL, and score. Useful for your UI to render source previews next to the answer.
Example
curl -X POST https://api.userepo.com/v1/ask \
-H "Authorization: Bearer repo_your_key" \
-H "Content-Type: application/json" \
-d '{
"query": "When does the brand-refresh project ship?",
"limit": 5
}'
const { answer, citations, context } = await fetch(
"https://api.userepo.com/v1/ask",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.REPO_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
query: "When does the brand-refresh project ship?",
limit: 5
})
}
).then(r => r.json());
console.log(answer);
for (const c of citations) {
const hit = context.find(h => h.sourceItemId === c.sourceItemId);
console.log(`[${c.index}] ${c.title} — ${hit.url}`);
}
import requests, os
r = requests.post(
"https://api.userepo.com/v1/ask",
headers={"Authorization": f"Bearer {os.environ['REPO_API_KEY']}"},
json={"query": "When does the brand-refresh project ship?", "limit": 5}
)
data = r.json()
print(data["answer"])
for c in data["citations"]:
hit = next((h for h in data["context"] if h["sourceItemId"] == c["sourceItemId"]), None)
print(f"[{c['index']}] {c['title']} — {hit['url'] if hit else ''}")
Behavior when retrieval is empty
If no hits match the query (within the calling key’s scope), Repo returns an answer like:I could not find company context for: <query>
citations + context are empty arrays. Your agent should treat this as “no grounded answer available” and either re-prompt the user, try a broader query, or fall back to its own knowledge with a disclaimer.
When to use this vs /v1/context
Use /v1/ask when | Use /v1/context when |
|---|---|
| You want the simplest one-call integration | You want to control the prompt or use your own LLM |
| Your agent doesn’t need to know about excluded providers | Your agent needs the full Context Contract |
| You’re fine with Repo’s default citation format | You’re rendering citations in custom UI |