Citations & Downloads: How to Show Sources Without Exposing Files
This guide explains how CustomGPT.ai citations work in the API and how to show sources while preventing file downloads.
1) What the public API supports
- 
Citations list in each answer (enable/disable and control visibility): - enable_citations(0–3),- citations_view_type(- user|show|hide),- hide_sources_from_responses(boolean),- enable_inline_citations_api(boolean).
 
- 
Inline citations in answers Add inline footnote markers via: - Per request: is_inline_citation: trueinPOST /api/v1/projects/{projectId}/chat/completions.
- Or globally: enable_inline_citations_apiin project settings.
 
- Per request: 
- 
Preview a cited file If a file is retained, the UI can open a secure preview via GET /api/v1/preview/{id}(whereidis the citation id). Note: this endpoint does not accept page/offset parameters.
Note on page/quote highlighting The public API and standard widget don’t expose page coordinates or quote‑level anchors. To get “open PDF on the exact page with the passage highlighted,” use the enterprise PDF viewer deployment. In the public API, consider splitting sources into logical sections or per‑page PDFs and naming them clearly; then use Page Metadata (title/description) so users can orient quickly. (See §4 for patterns.)
2) Keep citations but prevent downloads
There are two complementary approaches. You can use either or both:
A. Do not retain files after processing
When uploading via the Create/Update Agent endpoints, set the file data retention flag so files are not stored:
- Create agent (file upload supports data retention flag): POST /api/v1/projects(multipart form withfileandfile_data_retension).
- Update agent (replace/add files): POST /api/v1/projects/{projectId}(also supportsfile_data_retension).
If the file isn’t retained, GET /api/v1/preview/{id} won’t have anything to serve — users can still see which source was used (and any URL you provide), but can’t download the document.
B. Override the link users see in citations
Each crawled/ uploaded document becomes a Page. Update its Page Metadata so the citation card links wherever you want:
- Update Page Metadata: PUT /api/v1/projects/{projectId}/pages/{pageId}/metadatawith JSON body supportingtitle,url,description,image.
- How the UI picks the link: The citation’s card/title/URL are built from Page Metadata; you can confirm what the UI sees with GET /api/v1/projects/{projectId}/citations/{citationId}(returns Open Graph metadata).
Tip: Combine A + B. Don’t retain the file, and set
urlto a protected page (e.g., “why this content isn’t downloadable” or a sign‑in page).
3) API recipes
3.1 Enable inline citations globally
curl -X POST "https://app.customgpt.ai/api/v1/projects/{projectId}/settings" \
  -H "Authorization: Bearer $TOKEN" \
  -F "enable_inline_citations_api=true"This causes answers to include inline markers that map to the Sources list.
3.2 Request inline citations on a single response
curl -X POST "https://app.customgpt.ai/api/v1/projects/{projectId}/chat/completions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "messages":[{"role":"user","content":"What are the warranty terms?"}],
        "is_inline_citation": true
      }'3.3 Upload content without retaining the file
curl -X POST "https://app.customgpt.ai/api/v1/projects" \
  -H "Authorization: Bearer $TOKEN" \
  -F "project_name=Docs (No Retention)" \
  -F "file=@/path/to/file.pdf" \
  -F "file_data_retension=false"If you’re updating an existing agent, use POST /api/v1/projects/{projectId} with the same file_data_retension flag.
3.4 Point a citation to a custom URL (no download)
- List pages to get pageId:
curl -X GET "https://app.customgpt.ai/api/v1/projects/{projectId}/pages?limit=100" \
  -H "Authorization: Bearer $TOKEN"- Update Page Metadata:
curl -X PUT "https://app.customgpt.ai/api/v1/projects/{projectId}/pages/{pageId}/metadata" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "title": "Vendor Guide – Section 4",
        "url": "https://example.com/subscribers/vendor-guide-sec-4",
        "description": "Access requires a valid license.",
        "image": "https://example.com/og-image.png"
      }'- (Optional) Inspect what users will see in the citation card:
curl -X GET "https://app.customgpt.ai/api/v1/projects/{projectId}/citations/{citationId}" \
  -H "Authorization: Bearer $TOKEN"3.5 Batch override for many pages (pseudo‑workflow)
- 
List pages → iterate page IDs → PUT metadata with your custom url.
- 
If you need to retroactively remove downloadable files, delete the page and re‑upload with non‑retention: - DELETE /api/v1/projects/{projectId}/pages/{pageId}.
 
4) Improving “find the exact place” without the enterprise PDF viewer
Because the public API doesn’t expose page/offset, consider these patterns:
- Per‑page PDFs or sectioned files (e.g., Guide - p14.pdforGuide - Ch 3 §2.pdf). Then settitlein Page Metadata accordingly so the citation itself tells the user where in the source the info lives.
- Inline citations + short quote: enable is_inline_citation, and include a brief relevant quote in the answer for context; the footnote maps to the source.
5) Frequently asked questions
Q: Can I keep citations visible but remove the clickable link?
A: Not via a dedicated toggle. The settings you can control are enable_citations, citations_view_type, hide_sources_from_responses, and enable_inline_citations_api. To avoid downloads while keeping source visibility, use non‑retention and/or override the url in Page Metadata.
Q: How does the citation card’s title/URL get chosen?
A: From Page Metadata (title, url, description, image). You can read/update these via the Page Metadata endpoints; the citation Open Graph endpoint mirrors this data.
Q: Can I preview a cited file by API?
A: Yes: GET /api/v1/preview/{id}. If you didn’t retain the file, there’s nothing to preview. This endpoint doesn’t support page/offset highlighting.
Confirmation on Bill’s method
“Set the URL for a document using an API call so the citation links somewhere other than the original file.”
✅ Confirmed. Use Update Page Metadata to set a custom url for each page; the citation UI consumes this metadata for its link. Example endpoint:
PUT /api/v1/projects/{projectId}/pages/{pageId}/metadata with { "url": "https://your.site/explain-access" }.
If you also don’t want previews to exist at all, combine this with file non‑retention (upload with file_data_retension=false).
Optional snippets you can include in the docs
Node.js (fetch) – update a page’s citation link
await fetch(`https://app.customgpt.ai/api/v1/projects/${projectId}/pages/${pageId}/metadata`, {
  method: 'PUT',
  headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    title: 'Whitepaper – Page 14',
    url: 'https://example.com/paywalled/whitepaper#p14',
    description: 'Full text available for licensed users.'
  })
});Python (requests) – send a message with inline citations
import requests
r = requests.post(
  f"https://app.customgpt.ai/api/v1/projects/{project_id}/chat/completions",
  headers={"Authorization": f"Bearer {token}"},
  json={"messages":[{"role":"user","content":"Summarize warranty terms"}],
        "is_inline_citation": True}
)
print(r.json())Postman
Use the collection item “Preview file from citation” to test previews: GET {{baseUrl}}/preview/{{citationId}}. (Base URL already includes /api/v1.)
Limitations (today)
- No public API to jump to a specific page/offset or to return highlight spans inside a PDF; preview/{id}has no page/offset arguments.
- No dedicated toggle to “show source name but remove link.” Use non‑retention and/or override Page Metadata URL.
