# AddClaimDocuments - Advanced Documentation ## Model Shape ```javascript // ParentID is one top-level argument, not per-document SecureApi.AddClaimDocuments(ParentID, [ { Name: "invoice-2026-08.pdf", Type: { ID: 42 }, // required, ID > 0 File: { StorageName: "", IsURLOnly: false, ObjectSize: 482913 // real byte count } } ]) ``` ## Traps - No `Document.ID`. Each item is matched to an existing document by `Name` + `TreePrefix` + `Type.ID` (case-insensitive on Name/TreePrefix) - match updates in place, no match creates new. - `File.ObjectSize` defaults to `-1`. Non-URL files must set it to the real byte count or the call throws `"Non Url Files must have an object size."` - checked per item. - Files must already exist in S3 (see `FileService.GetUploadUrl`) before calling. - Missing `Name` -> `"All documents require a name."` Missing/invalid `Type` -> `"[Name] needs a Document Type."` - `ParentID < 1` -> `"Claims.ID was less than 1."` - Whole batch saves together - one failure fails all. ## Script Example ```javascript async () => { const documents = [ { Name: "invoice-2026-08.pdf", Type: { ID: 42 }, File: { StorageName: "3f2b9a1c-6e3d-4b2a-9c1f-8d7e6a5b4c3d", IsURLOnly: false, ObjectSize: 482913 } }, { Name: "photo-damage-01.jpg", Type: { ID: 42 }, File: { StorageName: "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d", IsURLOnly: false, ObjectSize: 1204882 } } ]; const result = await SecureApi.AddClaimDocuments(771360, documents); return result.map(d => ({ id: d.ID, fileId: d.File?.ID })); } ``` ## Cross-References | Need | Use | |------|-----| | Get a presigned upload URL | `FileService.GetUploadUrl(FileName, FileSize)` | | Add or update a single document | `SecureApi.SaveClaimDocument(Document)` | | How to get file bytes into that S3 location | See `FileService.GetUploadUrl` advanced docs - includes doing the PUT from outside the sandbox, you do not need to embed file content in the script |