Attachments Management API
Below is an updated REST API documentation for Attachments, now including a publicly accessible URL for fetching a file without authorization. All other endpoints remain the same, but we add one more section for this public route under Storage.
Note: There is an API client plus example available on: https://github.com/CatchTheTornado/open-agents-builder-client and https://github.com/CatchTheTornado/open-agents-builder-example
1. Overview
Attachments store binary files (images, PDFs, etc.) plus metadata in the database (AttachmentDTO
). You can:
- Create/Update (upsert) an attachment record (optionally with file upload)
- List attachments and search them via
/api/attachment
or/api/attachment/query
- Retrieve the raw file content in two ways:
- Authorized route:
GET /api/attachment/[id]
- Public route:
GET /storage/attachment/[databaseIdHash]/[id]
(no auth required)
- Authorized route:
- Delete an attachment record and its file
- Export all attachments in a ZIP archive
If your environment uses a SaaS mode with an encryption key, the content
field can be automatically encrypted.
2. Data Schema: AttachmentDTO
export const attachmentDTOSchema = z.object({ id: z.number().positive().optional(), displayName: z.string().optional().nullable(), safeNameIdentifier: z.string().optional().nullable(), description: z.string().optional().nullable(),
mimeType: z.string().optional().nullable(), type: z.string().optional().nullable(), json: z.string().optional().nullable(), extra: z.string().optional().nullable(),
size: z.number().positive().int().nullable(), storageKey: z.string().min(1), filePath: z.string().optional(),
content: z.string().optional().nullable(),
createdAt: z.string().default(() => getCurrentTS()), updatedAt: z.string().default(() => getCurrentTS()),
assignedTo: z.string().optional().nullable()});export type AttachmentDTO = z.infer<typeof attachmentDTOSchema>;
Key fields:
storageKey
: Uniquely identifies the file in storage (also used in the public route).displayName
: Friendly name.mimeType
: E.g.,image/png
.content
: If text was extracted from the file.size
: Size in bytes.extra
: Additional JSON metadata.createdAt
&updatedAt
: Timestamps.
3. Endpoints
3.1 Create / Update (Upsert) – PUT /api/attachment
Allows JSON-based or multipart/form-data-based upserts.
- JSON (no file upload).
- Form-data (binary file + JSON metadata in the
attachmentDTO
field).
See full code in the previous doc for how the server merges them and saves your file.
3.1.1 Example (JSON Body)
curl -X PUT \ "https://app.openagentsbuilder.com/api/attachment" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>" \ -H "Content-Type: application/json" \ -d '{ "storageKey": "file-key-123", "displayName": "example.txt", "mimeType": "text/plain", "content": "Some text content" }'
3.1.2 Example (Multipart/Form-Data)
curl -X PUT \ "https://app.openagentsbuilder.com/api/attachment" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>" \ -F "file=@/path/to/file.pdf" \ -F "attachmentDTO={\"storageKey\":\"my-pdf-file\",\"displayName\":\"Doc.pdf\",\"mimeType\":\"application/pdf\"}"
Response (HTTP 200 on success):
{ "message": "Data saved successfully!", "data": { "id": 101, "storageKey": "my-pdf-file", "displayName": "Doc.pdf", "mimeType": "application/pdf", ... }, "status": 200}
Using the TypeScript API Client
You can also upsert attachments via open-agents-builder-client. The default method uses a JSON body, but you can extend it to handle multipart uploads. Example:
import { OpenAgentsBuilderClient } from "open-agents-builder-client";
const client = new OpenAgentsBuilderClient({ apiKey: "YOUR_API_KEY", databaseIdHash: "YOUR_DATABASE_ID_HASH"});
async function upsertAttachmentClientExample() { const result = await client.attachment.upsertAttachment({ storageKey: "file-key-123", displayName: "example.txt", mimeType: "text/plain", content: "Some text content" });
console.log("Upserted attachment via client:", result);}
upsertAttachmentClientExample();
(For true multipart file uploads, see the example repo.)
3.2 List All – GET /api/attachment
Returns an array of all attachments. Basic filtering is possible with query parameters (e.g., ?storageKey=someKey
).
cURL:
curl -X GET \ "https://app.openagentsbuilder.com/api/attachment" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>"
Using the TypeScript API Client
async function listAttachmentsClient() { const result = await client.attachment.listAttachments(); console.log("All attachments:", result);}
listAttachmentsClient();
3.3 Search / Pagination – GET /api/attachment/query
Enables advanced searching with limit
, offset
, orderBy
, and query
.
curl -X GET \ "https://app.openagentsbuilder.com/api/attachment/query?limit=5&offset=0&orderBy=createdAt&query=jpg" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>"
Returns a paginated structure:
{ "rows": [...AttachmentDTO...], "total": 25, "limit": 5, "offset": 0, "orderBy": "createdAt", "query": "jpg"}
Using the TypeScript API Client
async function queryAttachmentsClient() { const result = await client.attachment.queryAttachments({ limit: 5, offset: 0, orderBy: "createdAt", query: "jpg" }); console.log("Queried attachments:", result);}
queryAttachmentsClient();
3.4 Retrieve Binary (Authorized) – GET /api/attachment/[id]
Requires authorization and database-id-hash
. Returns the raw file content with Content-Type: application/octet-stream
(can be changed if you store mimeType
).
curl -X GET \ "https://app.openagentsbuilder.com/api/attachment/my-file-key" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>" \ -o downloaded-file
Using the TypeScript API Client
Note: The default
attachment
client does not have a special method for downloading raw binary. You can uselistAttachments
orqueryAttachments
to get metadata, then fetch the binary separately withfetch
.
async function downloadAttachmentBinary(storageKey: string) { const response = await fetch( `https://app.openagentsbuilder.com/api/attachment/${storageKey}`, { headers: { "Authorization": `Bearer ${process.env.OPEN_AGENTS_BUILDER_API_KEY}`, "database-id-hash": "YOUR_DATABASE_ID_HASH" } } );
if (!response.ok) { throw new Error(`Error fetching attachment: ${response.statusText}`); }
const blob = await response.blob(); // or arrayBuffer() console.log("Downloaded blob:", blob); return blob;}
3.5 Retrieve Binary (Public / No Auth) – GET /storage/attachment/[databaseIdHash]/[id]
New: This route does NOT require authentication. Useful for public-facing file URLs.
[databaseIdHash]
: The user’s DB hash.[id]
: The file’sstorageKey
.
If found, returns the file with the stored mimeType
. Otherwise, 404
.
cURL:
curl -X GET \ "https://app.openagentsbuilder.com/storage/attachment/35f5c5b139a6b569d4649b7.../my-file-key" \ -o downloaded-file
(No Authorization
or database-id-hash
headers needed.)
TypeScript:
async function fetchPublicAttachment(databaseIdHash: string, storageKey: string) { const response = await fetch( `https://app.openagentsbuilder.com/storage/attachment/${databaseIdHash}/${storageKey}` ); if (!response.ok) { throw new Error("File not found or server error"); } // e.g., blob or arrayBuffer const blob = await response.blob(); console.log("Public file blob:", blob); return blob;}
(No official client method exists for public retrieval since it’s unauthenticated.)
3.6 Delete – DELETE /api/attachment/[id]
Removes the DB record and also deletes the file from storage if found.
curl -X DELETE \ "https://app.openagentsbuilder.com/api/attachment/my-file-key" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>"
If success:
{ "message": "Data deleted successfully!", "status": 200}
If not found:
{ "message": "Record not found", "status": 404}
Using the TypeScript API Client
async function deleteAttachmentClientExample(storageKey: string) { const deleted = await client.attachment.deleteAttachment(storageKey); console.log("Deleted attachment:", deleted);}
deleteAttachmentClientExample("my-file-key");
3.7 Export – GET /api/attachment/export
Creates a ZIP with:
index.md
andindex.html
listing attachments.- Each file itself included.
- If an attachment has
.content
, it also includes.md
and.html
versions of that text. attachments.json
with all metadata.
cURL:
curl -X GET \ "https://app.openagentsbuilder.com/api/attachment/export" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>" \ -o attachments.zip
Using the TypeScript API Client
The default client does not have a dedicated export method, but you can extend it if needed.
import { BaseClient } from "open-agents-builder-client";
class ExtendedAttachmentApi extends BaseClient { public async exportAttachments(): Promise<Blob> { const url = `${this.baseUrl}/api/attachment/export`; const resp = await fetch(url, { method: "GET", headers: { "Authorization": `Bearer ${this.apiKey}`, "database-id-hash": this.databaseIdHash } }); if (!resp.ok) { throw new Error(`Error exporting attachments: ${resp.statusText}`); } return resp.blob(); }}
4. Encryption Details
If a SaaS storageKey
is provided:
- The field
content
is encrypted in the database. - On read (
GET
or search), it’s automatically decrypted. - The binary file stored in your system’s storage is not automatically encrypted – only the
content
string in DB. - If you need end-to-end encryption for the file itself, adapt the
StorageService
to encrypt the file before saving.
5. Error Handling
- 400 Bad Request: Missing necessary fields (
storageKey
), or invalid data inPUT
. - 404 Not Found: The
storageKey
does not exist in DB or file system (onGET
orDELETE
). - 499 / 500 Internal Server Error: Server or database failure.
- 401 / 403 Unauthorized: For the authorized endpoints only, if missing
Authorization
ordatabase-id-hash
. - Public route (
GET /storage/attachment/[databaseIdHash]/[id]
) does not require authentication.
6. Summary of Attachment Endpoints
Endpoint | Method | Requires Auth? | Purpose |
---|---|---|---|
/api/attachment | PUT | Yes | Upsert (create/update) attachment with optional file upload or JSON body. |
/api/attachment | GET | Yes | List all attachments (array). |
/api/attachment/query?limit=&offset=&orderBy=&query= | GET | Yes | Paginated search across attachments. |
/api/attachment/[id] (GET) | GET | Yes | Retrieve binary content. id = storageKey . Sets Content-Type=application/octet-stream . |
/storage/attachment/[databaseIdHash]/[id] (GET) | GET | No | Public: fetches the file with no authentication required. |
/api/attachment/[id] (DELETE) | DELETE | Yes | Deletes the DB record and the file from storage. |
/api/attachment/export | GET | Yes | Export all attachments in a ZIP (index.md/html , each file, plus .md/html if content exists, JSON). |
This completes the Attachments documentation, now featuring a public route (/storage/attachment/[databaseIdHash]/[id]
) for unauthenticated file access.