Search
curl --request POST \
--url https://api.userepo.com/v1/search \
--header 'Content-Type: application/json' \
--data '
{
"query": "<string>",
"limit": 123
}
'import requests
url = "https://api.userepo.com/v1/search"
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/search', 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/search",
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/search"
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/search")
.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/search")
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{
"query": "<string>",
"hits": [
{
"sourceItemId": "<string>",
"title": "<string>",
"content": "<string>",
"url": "<string>",
"provider": "<string>",
"score": 123,
"metadata": {},
"syncedAt": "<string>"
}
]
}Reference
Search
Vector search across your organization’s memory. Returns ranked hits with metadata.
POST
/
v1
/
search
Search
curl --request POST \
--url https://api.userepo.com/v1/search \
--header 'Content-Type: application/json' \
--data '
{
"query": "<string>",
"limit": 123
}
'import requests
url = "https://api.userepo.com/v1/search"
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/search', 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/search",
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/search"
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/search")
.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/search")
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{
"query": "<string>",
"hits": [
{
"sourceItemId": "<string>",
"title": "<string>",
"content": "<string>",
"url": "<string>",
"provider": "<string>",
"score": 123,
"metadata": {},
"syncedAt": "<string>"
}
]
}The simplest retrieval endpoint. Use it when you want raw hits and will craft your own prompt downstream. For grounded answers with citations + exclusions, use
/v1/context or /v1/ask.
Required action
search — see Authentication → Actions.
Cost
Each successful call consumes 1 credit. On Builder tier this is hard-blocked at the monthly cap. On Studio/Scale tiers calls past the cap are billed at $0.015 per answer overage. See Billing.Body
string
required
The user-facing question or search phrase. Sent as-is to the embedding model.
integer
default:"8"
Maximum number of hits to return. Min 1, max 25.
Response
{
"query": "What did we decide about the brand color?",
"hits": [
{
"sourceItemId": "9c0e7a3f-1234-4abc-bdef-1234567890ab",
"title": "Brand decisions",
"content": "We're keeping the lime-green accent because Q2 testing showed...",
"url": "https://www.notion.so/Brand-decisions-...",
"provider": "notion",
"score": 0.8432,
"metadata": {
"workspaceId": "ws-1",
"workspaceName": "Repo Labs"
},
"syncedAt": "2026-05-30T20:00:00Z"
}
]
}
string
Echo of the input query for convenience.
array
Ranked array of source items matching the query, ordered by
score descending.Show Hit fields
Show Hit fields
string
Stable Repo UUID for the source item.
string
Human-facing title (Notion page title, Slack message preview, etc.).
string
The matched chunk text.
string
Deep-link back to the original source.
string
slack, google_drive, notion, or gmail.number
Cosine similarity to the query embedding (0.0–1.0).
object
Provider-specific metadata (workspace IDs, channel names, sender info, etc.).
string
When this source was last synced by Repo.
Example
curl -X POST https://api.userepo.com/v1/search \
-H "Authorization: Bearer repo_your_key" \
-H "Content-Type: application/json" \
-d '{"query": "Q3 OKRs", "limit": 5}'
const res = await fetch("https://api.userepo.com/v1/search", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.REPO_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ query: "Q3 OKRs", limit: 5 })
});
const { hits } = await res.json();
import requests, os
r = requests.post(
"https://api.userepo.com/v1/search",
headers={"Authorization": f"Bearer {os.environ['REPO_API_KEY']}"},
json={"query": "Q3 OKRs", "limit": 5}
)
print(r.json()["hits"])
Provider scoping
If the calling key hasallowedProviders set, hits from excluded providers are filtered out server-side before the response is built. See Scopes for details. The exclusions array that explains why something was filtered is only returned by /v1/context — /v1/search is silent about scope filtering.