Skip to content

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:

  1. Create/Update (upsert) an attachment record (optionally with file upload)
  2. List attachments and search them via /api/attachment or /api/attachment/query
  3. Retrieve the raw file content in two ways:
    • Authorized route: GET /api/attachment/[id]
    • Public route: GET /storage/attachment/[databaseIdHash]/[id] (no auth required)
  4. Delete an attachment record and its file
  5. 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.

  1. JSON (no file upload).
  2. 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)

Terminal window
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)

Terminal window
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 AllGET /api/attachment

Returns an array of all attachments. Basic filtering is possible with query parameters (e.g., ?storageKey=someKey).

cURL:

Terminal window
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 / PaginationGET /api/attachment/query

Enables advanced searching with limit, offset, orderBy, and query.

Terminal window
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).

Terminal window
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 use listAttachments or queryAttachments to get metadata, then fetch the binary separately with fetch.

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’s storageKey.

If found, returns the file with the stored mimeType. Otherwise, 404.

cURL:

Terminal window
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 DeleteDELETE /api/attachment/[id]

Removes the DB record and also deletes the file from storage if found.

Terminal window
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 ExportGET /api/attachment/export

Creates a ZIP with:

  • index.md and index.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:

Terminal window
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 in PUT.
  • 404 Not Found: The storageKey does not exist in DB or file system (on GET or DELETE).
  • 499 / 500 Internal Server Error: Server or database failure.
  • 401 / 403 Unauthorized: For the authorized endpoints only, if missing Authorization or database-id-hash.
  • Public route (GET /storage/attachment/[databaseIdHash]/[id]) does not require authentication.

6. Summary of Attachment Endpoints

EndpointMethodRequires Auth?Purpose
/api/attachmentPUTYesUpsert (create/update) attachment with optional file upload or JSON body.
/api/attachmentGETYesList all attachments (array).
/api/attachment/query?limit=&offset=&orderBy=&query=GETYesPaginated search across attachments.
/api/attachment/[id] (GET)GETYesRetrieve binary content. id = storageKey. Sets Content-Type=application/octet-stream.
/storage/attachment/[databaseIdHash]/[id] (GET)GETNoPublic: fetches the file with no authentication required.
/api/attachment/[id] (DELETE)DELETEYesDeletes the DB record and the file from storage.
/api/attachment/exportGETYesExport 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.