curl -X GET \
"https://bouncer.nunu.ai/file-storage/my-project?include_metadata=true" \
-H "X-Api-Key: YOUR_API_TOKEN"
curl -X GET \
"https://bouncer.nunu.ai/file-storage/my-project?agent_id=a1b2c3&test_case_id=t1t2t3&include_metadata=true" \
-H "X-Api-Key: YOUR_API_TOKEN"
const projectId = "my-project";
const params = new URLSearchParams({
include_metadata: "true",
agent_id: "a1b2c3",
test_case_id: "t1t2t3",
});
const response = await fetch(
`https://bouncer.nunu.ai/file-storage/${projectId}?${params}`,
{
headers: {
"X-Api-Key": process.env.NUNU_API_TOKEN,
},
}
);
const data = await response.json();
import requests
import os
project_id = "my-project"
response = requests.get(
f"https://bouncer.nunu.ai/file-storage/{project_id}",
headers={"X-Api-Key": os.environ["NUNU_API_TOKEN"]},
params={
"include_metadata": True,
"agent_id": "a1b2c3",
"test_case_id": "t1t2t3",
},
)
data = response.json()
{
"projectId": "my-project",
"count": 3,
"sections": [
{
"scope": "project",
"count": 2,
"files": [
{
"filename": "game-design.md",
"path": "game-design.md",
"size": 4096,
"uploaded": "2026-04-12T10:30:00.000Z",
"etag": "9a3b4c5d6e7f8090a1b2c3d4e5f60718",
"metadata": {
"description": "High-level design overview",
"summary": "Mechanics, levels, and progression",
"keywords": ["design", "gameplay"]
}
},
{
"filename": "rules.txt",
"path": "subdir/rules.txt",
"size": 1234,
"uploaded": "2026-04-12T10:31:00.000Z",
"etag": "0a1b2c3d4e5f60718a3b4c5d6e7f8090"
}
]
},
{
"scope": "agent",
"id": "a1b2c3",
"count": 1,
"files": [
{
"filename": "agent-prompt.md",
"path": "agent-prompt.md",
"size": 512,
"uploaded": "2026-04-12T10:35:00.000Z",
"etag": "1b2c3d4e5f60718a3b4c5d6e7f80909a"
}
]
},
{
"scope": "test_case",
"id": "t1t2t3",
"count": 0,
"files": []
}
]
}
Knowledge
List Knowledge Files
List knowledge files for a project. Always returns project-scope files; conditionally includes agent- and/or test-case-scope files when their IDs are passed as query parameters.
GET
/
file-storage
/
{projectId}
curl -X GET \
"https://bouncer.nunu.ai/file-storage/my-project?include_metadata=true" \
-H "X-Api-Key: YOUR_API_TOKEN"
curl -X GET \
"https://bouncer.nunu.ai/file-storage/my-project?agent_id=a1b2c3&test_case_id=t1t2t3&include_metadata=true" \
-H "X-Api-Key: YOUR_API_TOKEN"
const projectId = "my-project";
const params = new URLSearchParams({
include_metadata: "true",
agent_id: "a1b2c3",
test_case_id: "t1t2t3",
});
const response = await fetch(
`https://bouncer.nunu.ai/file-storage/${projectId}?${params}`,
{
headers: {
"X-Api-Key": process.env.NUNU_API_TOKEN,
},
}
);
const data = await response.json();
import requests
import os
project_id = "my-project"
response = requests.get(
f"https://bouncer.nunu.ai/file-storage/{project_id}",
headers={"X-Api-Key": os.environ["NUNU_API_TOKEN"]},
params={
"include_metadata": True,
"agent_id": "a1b2c3",
"test_case_id": "t1t2t3",
},
)
data = response.json()
{
"projectId": "my-project",
"count": 3,
"sections": [
{
"scope": "project",
"count": 2,
"files": [
{
"filename": "game-design.md",
"path": "game-design.md",
"size": 4096,
"uploaded": "2026-04-12T10:30:00.000Z",
"etag": "9a3b4c5d6e7f8090a1b2c3d4e5f60718",
"metadata": {
"description": "High-level design overview",
"summary": "Mechanics, levels, and progression",
"keywords": ["design", "gameplay"]
}
},
{
"filename": "rules.txt",
"path": "subdir/rules.txt",
"size": 1234,
"uploaded": "2026-04-12T10:31:00.000Z",
"etag": "0a1b2c3d4e5f60718a3b4c5d6e7f8090"
}
]
},
{
"scope": "agent",
"id": "a1b2c3",
"count": 1,
"files": [
{
"filename": "agent-prompt.md",
"path": "agent-prompt.md",
"size": 512,
"uploaded": "2026-04-12T10:35:00.000Z",
"etag": "1b2c3d4e5f60718a3b4c5d6e7f80909a"
}
]
},
{
"scope": "test_case",
"id": "t1t2t3",
"count": 0,
"files": []
}
]
}
Permission Required: any API key scoped to the requested project
Knowledge endpoints are served by the bouncer service at
https://bouncer.nunu.ai, not the main nunu.ai/api/v1 host. Use the same
X-Api-Key header for authentication.| Scope | Path on storage | Visible to |
|---|---|---|
project | {projectId}/project/ | Every run in the project |
agent | {projectId}/agent/{agentId}/ | Runs that use the given agent |
test_case | {projectId}/test_case/{testCaseId}/ | Runs that execute the given test |
Path Parameters
string
required
The nunu.ai project ID. Must match the project the API key is scoped to.
Query Parameters
string
Include files from
agent/{agent_id}/ in the response.string
Include files from
test_case/{test_case_id}/ in the response.boolean
default:"false"
When
true, attach the parsed metadata (description, summary,
keywords) for each file. Metadata is stored alongside each file as a
hidden .{name}.meta.json sidecar.Response
string
required
Echo of the path parameter.
integer
required
Total number of files across all included sections.
Section[]
required
One section per scope returned. The
project section is always present;
other sections are only present when the corresponding query parameter is
set.Show Section properties
Show Section properties
string
One of
project, agent, test_case.string
The agent or test case ID. Omitted for the
project section.integer
Number of files in this section.
File[]
Files in this section. See File Object below.
File Object
string
required
Basename of the file (no directory prefix).
string
required
Path of the file relative to the scope root (may include subdirectories).
integer
required
File size in bytes.
string
required
ISO 8601 timestamp when the file was last written.
string
required
Object ETag.
object
curl -X GET \
"https://bouncer.nunu.ai/file-storage/my-project?include_metadata=true" \
-H "X-Api-Key: YOUR_API_TOKEN"
curl -X GET \
"https://bouncer.nunu.ai/file-storage/my-project?agent_id=a1b2c3&test_case_id=t1t2t3&include_metadata=true" \
-H "X-Api-Key: YOUR_API_TOKEN"
const projectId = "my-project";
const params = new URLSearchParams({
include_metadata: "true",
agent_id: "a1b2c3",
test_case_id: "t1t2t3",
});
const response = await fetch(
`https://bouncer.nunu.ai/file-storage/${projectId}?${params}`,
{
headers: {
"X-Api-Key": process.env.NUNU_API_TOKEN,
},
}
);
const data = await response.json();
import requests
import os
project_id = "my-project"
response = requests.get(
f"https://bouncer.nunu.ai/file-storage/{project_id}",
headers={"X-Api-Key": os.environ["NUNU_API_TOKEN"]},
params={
"include_metadata": True,
"agent_id": "a1b2c3",
"test_case_id": "t1t2t3",
},
)
data = response.json()
{
"projectId": "my-project",
"count": 3,
"sections": [
{
"scope": "project",
"count": 2,
"files": [
{
"filename": "game-design.md",
"path": "game-design.md",
"size": 4096,
"uploaded": "2026-04-12T10:30:00.000Z",
"etag": "9a3b4c5d6e7f8090a1b2c3d4e5f60718",
"metadata": {
"description": "High-level design overview",
"summary": "Mechanics, levels, and progression",
"keywords": ["design", "gameplay"]
}
},
{
"filename": "rules.txt",
"path": "subdir/rules.txt",
"size": 1234,
"uploaded": "2026-04-12T10:31:00.000Z",
"etag": "0a1b2c3d4e5f60718a3b4c5d6e7f8090"
}
]
},
{
"scope": "agent",
"id": "a1b2c3",
"count": 1,
"files": [
{
"filename": "agent-prompt.md",
"path": "agent-prompt.md",
"size": 512,
"uploaded": "2026-04-12T10:35:00.000Z",
"etag": "1b2c3d4e5f60718a3b4c5d6e7f80909a"
}
]
},
{
"scope": "test_case",
"id": "t1t2t3",
"count": 0,
"files": []
}
]
}
Authorizations
API key for authentication
Path Parameters
The nunu.ai project ID. Must match the project the API key is scoped to.
Query Parameters
Include files from agent/{agent_id}/ in the response.
Include files from test_case/{test_case_id}/ in the response.
When true, attach parsed metadata (description, summary, keywords) for each file from its .{name}.meta.json sidecar.
Response
Successful response