# Assets

> Source: https://agilitycms.com/docs/javascript/management-sdk/assets

The asset methods cover uploading files, browsing the media library, organizing assets into folders and galleries, and deleting them. In JavaScript the methods hang off `apiClient.assetMethods`; in .NET they are on the `AssetMethods` class, reached through `client.assetMethods`.

> **Note:** The upload APIs are not symmetrical. The JavaScript SDK posts a `FormData` object; the .NET SDK takes a `Dictionary<string, string>` that maps a file name to the local directory containing the file.

## Retrieving assets

### Get media list

Returns a paginated list of media assets in the instance.

<div class="code-tabs" data-tabs="JavaScript,.NET">

```ts
// Get paginated media list
const mediaList = await apiClient.assetMethods.getMediaList(
  50,   // pageSize
  0,    // recordOffset
  guid  // instance GUID
);

console.log('Total media items:', mediaList.length);
mediaList.forEach(media => {
  console.log(`- ${media.fileName} (${media.size} bytes)`);
});
```

```csharp
var mediaList = await client.assetMethods.GetMediaList(
    pageSize: 50,
    recordOffset: 0,
    guid: guid
);

Console.WriteLine($"Total assets: {mediaList?.Count}");
foreach (var media in mediaList?.MediaItems ?? [])
{
    Console.WriteLine($"{media.FileName} - {media.Url}");
}
```

</div>

| Parameter | Description |
| --- | --- |
| `pageSize` | Number of records to return per page. |
| `recordOffset` | Zero-based index of the first record to return. |
| `guid` | Instance GUID. |

**.NET signature:** `Task<AssetMediaList?> GetMediaList(int? pageSize, int? recordOffset, string guid)`

### Get asset by ID

Looks up a single asset by its numeric media ID.

```csharp
var asset = await client.assetMethods.GetAssetByID(mediaID, guid);
Console.WriteLine($"Asset: {asset?.FileName} - {asset?.Url}");
```

**Signature:** `Task<Media?> GetAssetByID(int? mediaID, string guid)`

> Not documented for the JavaScript SDK.

### Get asset by URL

Looks up a single asset by its CDN URL. Note the method-name casing differs between the SDKs: `getAssetByUrl` in JavaScript, `GetAssetByURL` in .NET.

<div class="code-tabs" data-tabs="JavaScript,.NET">

```ts
// Find asset by URL
const asset = await apiClient.assetMethods.getAssetByUrl(
  'https://cdn.aglty.io/your-guid/media/image.jpg',
  guid
);

if (asset) {
  console.log('Found asset:', asset.fileName);
}
```

```csharp
var asset = await client.assetMethods.GetAssetByURL(
    "https://cdn.aglty.io/your-guid/media/image.jpg",
    guid
);

if (asset != null)
{
    Console.WriteLine($"Found: {asset.FileName} (ID: {asset.MediaID})");
}
```

</div>

**.NET signature:** `Task<Media?> GetAssetByURL(string? url, string guid)`

## Uploading files

Both SDKs upload one or more files into a folder path in the Agility media library, optionally assigning them to a gallery. Pass `-1` for the gallery/grouping ID when the files do not belong to a gallery, and an empty folder path to upload to the root.

<div class="code-tabs" data-tabs="JavaScript,.NET">

```ts
const FormData = require('form-data');
const fs = require('fs');

// Create form data
const form = new FormData();
form.append('files', fs.createReadStream('hero-image.jpg'), 'hero-image.jpg');

const uploadedAssets = await apiClient.assetMethods.upload(
  form,
  'images/heroes', // folderPath ('' for root)
  guid,
  -1               // galleryId (-1 for no gallery)
);

const uploadedAsset = uploadedAssets[0];
console.log('Asset URL:', uploadedAsset.url);
console.log('Media ID:', uploadedAsset.mediaID);
```

```csharp
// Key = filename, Value = local directory path
var files = new Dictionary<string, string>
{
    { "hero-image.jpg", "/path/to/directory" },
    { "logo.png", "/path/to/directory" }
};

var uploaded = await client.assetMethods.Upload(
    files: files,
    guid: guid,
    agilityFolderPath: "images/heroes", // folder path in Agility
    groupingID: -1                      // gallery ID (-1 for none)
);

foreach (var media in uploaded)
{
    Console.WriteLine($"Uploaded: {media.FileName} - {media.Url}");
}
```

</div>

| JavaScript parameter | .NET parameter | Description |
| --- | --- | --- |
| `form` | `files` | JavaScript: a `FormData` instance with one or more `files` entries. .NET: a dictionary of file name to local directory path. |
| `folderPath` | `agilityFolderPath` | Destination folder path in the Agility media library. Empty string uploads to the root. |
| `guid` | `guid` | Instance GUID. |
| `galleryId` | `groupingID` | Gallery to add the assets to; `-1` for none. |

**.NET signature:** `Task<List<Media>?> Upload(Dictionary<string, string> files, string guid, string agilityFolderPath, int groupingID = -1)`

Both SDKs return a collection of the created media items, so the uploaded asset's `url` / `Url` and `mediaID` / `MediaID` are available immediately.

### Bulk upload

A single .NET `Upload` call already accepts multiple entries in the `files` dictionary. In JavaScript, loop over the files and upload them individually, collecting successes and failures.

```ts
async function uploadMultipleFiles(
  filePaths: string[],
  folderPath: string,
  guid: string
) {
  const results = [];

  for (const filePath of filePaths) {
    try {
      const form = new FormData();
      const fileName = path.basename(filePath);
      form.append('files', fs.createReadStream(filePath), fileName);

      const uploadedAssets = await apiClient.assetMethods.upload(
        form,
        folderPath,
        guid,
        -1
      );

      results.push({
        success: true,
        fileName,
        asset: uploadedAssets[0]
      });
    } catch (error) {
      results.push({
        success: false,
        fileName: path.basename(filePath),
        error: error.message
      });
    }
  }

  return results;
}
```

### Organizing uploads by type and date

The folder path is just a string, so you can derive it from the file extension and the current date to keep the media library tidy.

```ts
// Organize assets by type and date
async function organizeAssetUpload(
  filePath: string,
  guid: string
) {
  const fileName = path.basename(filePath);
  const fileExt = path.extname(fileName).toLowerCase();
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, '0');

  // Determine folder based on file type
  let folderPath = '';
  if (['.jpg', '.jpeg', '.png', '.webp', '.gif'].includes(fileExt)) {
    folderPath = `images/${year}/${month}`;
  } else if (['.pdf', '.doc', '.docx'].includes(fileExt)) {
    folderPath = `documents/${year}/${month}`;
  } else if (['.mp4', '.mov', '.avi'].includes(fileExt)) {
    folderPath = `videos/${year}/${month}`;
  } else {
    folderPath = `other/${year}/${month}`;
  }

  const form = new FormData();
  form.append('files', fs.createReadStream(filePath), fileName);

  return await apiClient.assetMethods.upload(form, folderPath, guid, -1);
}
```

## Folders

### Create folder

Creates a folder in the Agility media library.

```csharp
var folder = await client.assetMethods.CreateFolder(
    originKey: "images/new-folder",
    guid: guid
);
Console.WriteLine($"Created folder: {folder?.OriginKey}");
```

**Signature:** `Task<Media?> CreateFolder(string originKey, string guid)`

> Not documented for the JavaScript SDK — in JavaScript, uploading to a folder path creates it implicitly.

### Move file

Moves an asset to a different folder.

```csharp
var moved = await client.assetMethods.MoveFile(
    mediaID: mediaID,
    newFolder: "images/archive",
    guid: guid
);
Console.WriteLine($"Moved to: {moved?.OriginKey}");
```

**Signature:** `Task<Media?> MoveFile(int? mediaID, string? newFolder, string guid)`

> Not documented for the JavaScript SDK.

### Delete folder

Deletes an entire folder, identified by its origin key (the folder path). Pass `null` for the media ID when deleting a folder rather than a file.

```ts
// Delete entire folder
await apiClient.assetMethods.deleteFolder(
  'images/old-folder', // originKey (folder path)
  guid,
  null // mediaId (null for folder deletion)
);
console.log('Folder deleted successfully');
```

> Not available in the .NET SDK yet.

## Deleting assets

### Delete file

Deletes a single asset by media ID.

<div class="code-tabs" data-tabs="JavaScript,.NET">

```ts
// Delete asset by media ID
await apiClient.assetMethods.deleteFile(mediaId, guid);
console.log('Asset deleted successfully');
```

```csharp
var result = await client.assetMethods.DeleteFile(mediaID, guid);
Console.WriteLine($"Deleted: {result}");
```

</div>

**.NET signature:** `Task<string?> DeleteFile(int? mediaID, string guid)`

## Galleries

Galleries (media groupings) let you group assets together. Both SDKs can list galleries and fetch one by name; the .NET SDK additionally supports fetching by ID, saving, and deleting.

### Get galleries

Returns a paginated list of galleries, optionally filtered by a search term.

<div class="code-tabs" data-tabs="JavaScript,.NET">

```ts
// Get all galleries
const galleries = await apiClient.assetMethods.getGalleries(
  guid,
  '',     // searchTerm
  50,     // pageSize
  0       // rowIndex
);

galleries.forEach(gallery => {
  console.log(`Gallery: ${gallery.galleryName} (${gallery.mediaCount} items)`);
});
```

```csharp
var galleries = await client.assetMethods.GetGalleries(
    guid: guid,
    search: null,      // optional search term
    pageSize: 50,
    rowIndex: 0
);

foreach (var gallery in galleries?.Items ?? [])
{
    Console.WriteLine($"{gallery.GalleryName} ({gallery.MediaCount} items)");
}
```

</div>

| Parameter | Description |
| --- | --- |
| `guid` | Instance GUID. |
| `searchTerm` / `search` | Optional term to filter galleries by name. |
| `pageSize` | Number of galleries to return. |
| `rowIndex` | Zero-based index of the first gallery to return. |

**.NET signature:** `Task<AssetGalleries> GetGalleries(string guid, string? search = null, int? pageSize = null, int? rowIndex = null)`

### Get gallery by name

<div class="code-tabs" data-tabs="JavaScript,.NET">

```ts
// Find specific gallery
const gallery = await apiClient.assetMethods.getGalleryByName(
  guid,
  'Product Images'
);

if (gallery) {
  console.log('Gallery ID:', gallery.galleryID);
  console.log('Media count:', gallery.mediaCount);
}
```

```csharp
var gallery = await client.assetMethods.GetGalleryByName(guid, "Product Images");
Console.WriteLine($"Gallery ID: {gallery.GalleryID}, Items: {gallery.MediaCount}");
```

</div>

**.NET signature:** `Task<AssetMediaGrouping> GetGalleryByName(string guid, string galleryName)`

### Get gallery by ID

```csharp
var gallery = await client.assetMethods.GetGalleryById(guid, galleryId);
Console.WriteLine($"Gallery: {gallery.GalleryName}");
```

**Signature:** `Task<AssetMediaGrouping> GetGalleryById(string guid, int id)`

> Not documented for the JavaScript SDK.

### Save gallery

Creates or updates a gallery. Use `GalleryID = -1` to create a new one.

```csharp
using agility.models;

var gallery = new AssetMediaGrouping
{
    GalleryID = -1, // -1 for new
    GalleryName = "New Gallery"
};

var saved = await client.assetMethods.SaveGallery(guid, gallery);
Console.WriteLine($"Saved gallery ID: {saved.GalleryID}");
```

**Signature:** `Task<AssetMediaGrouping> SaveGallery(string guid, AssetMediaGrouping gallery)`

> Not documented for the JavaScript SDK.

### Delete gallery

```csharp
var result = await client.assetMethods.DeleteGallery(guid, galleryId);
Console.WriteLine($"Deleted: {result}");
```

**Signature:** `Task<string?> DeleteGallery(string guid, int? id)`

> Not documented for the JavaScript SDK.

## Default container

Retrieves the default asset container configuration for the instance.

```csharp
var container = await client.assetMethods.GetDefaultContainer(guid);
Console.WriteLine($"Container ID: {container.ContainerID}");
```

**Signature:** `Task<AssetContainer> GetDefaultContainer(string guid)`

> Not documented for the JavaScript SDK.

## Error handling

Asset calls throw on failure, so wrap them in a try/catch.

<div class="code-tabs" data-tabs="JavaScript,.NET">

```ts
try {
  const asset = await apiClient.assetMethods.getAssetByUrl(url, guid);
} catch (error) {
  console.error('Error:', error.message);
}
```

```csharp
try
{
    var asset = await client.assetMethods.GetAssetByID(mediaID, guid);
}
catch (ApplicationException ex)
{
    Console.Error.WriteLine($"Error: {ex.Message}");
}
```

</div>
