# Working with Snaps

This guide walks you through managing Snaps programmatically using Luxonis Hub GraphQL API. You'll learn how to list snaps,
retrieve detailed information, and delete them.

> **Creating Snaps**
> To send or create Snaps from your applications, you must use the DepthAI. Check out the [Snaps in DepthAI](https://docs.luxonis.com/software-v3/depthai/tutorials/snaps.md) documentation for details on how to emit Snaps from your applications.

This guide focuses on querying, filtering, and managing existing Snaps via GraphQL API.

## Prerequisites

Before starting, you should be familiar with GraphQL basics. If you're new to GraphQL, check out [About
GraphQL](https://docs.luxonis.com/cloud/api/graphql.md).

You'll also need an API key to authenticate your requests.

To interact with Luxonis Hub API, you need an API key. API keys provide full access to your team's resources.

[Follow API Keys documentation](https://docs.luxonis.com/cloud/api/api-keys.md) to create a key in the Luxonis Hub web UI.

Once you have your API key, include it in the `Authorization` header:

```bash
Authorization: Bearer <your_api_key>
```

Use the `snaps` query to retrieve a list of all snaps in your team. This query supports cursor-based pagination for efficient
navigation through large datasets.

### Basic List Query

```graphql
query {
  team {
    snaps(first: 10) {
      nodes {
        id
        name
        createdAt
        tags
        extras
        files {
          id
          name
          classification
        }
        sourceDeviceId
        sourceAppIdentifier
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
```

Query breakdown:

 * `first: 10` - limits results to 10 snaps
 * `nodes` - array of snap objects
 * `pageInfo` - pagination metadata (cursor for next page)

Snap fields explained:

 * `id`: Unique snap identifier
 * `name`: Snap name (e.g., `"car_detected"`, `"data_collection"`)
 * `createdAt`: Timestamp when snap was created
 * `tags`: Array of tags for grouping (e.g., `"night"`, `"dataset_v2"`)
 * `extras`: JSON object with custom key-value pairs for searchable metadata
 * `files`: Array of attached files (images, videos, point clouds, etc.)
 * `sourceDeviceId`: Device ID that created the snap
 * `sourceAppIdentifier`: App that created the snap

### Pagination

To fetch the next page, use the `endCursor` from the previous response:

```graphql
query($after: String) {
  team {
    snaps(first: 10, after: $after) {
      nodes {
        id
        name
        createdAt
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
```

Variables:

```json
{
  "after": "cursor_from_previous_response"
}
```

### Filtering Snaps

Filter snaps by various criteria to find specific data:

Filter by time range:

```graphql
query($from: DateTime!, $to: DateTime!) {
  team {
    snaps(
      first: 10,
      filter: {
        createdFrom: $from,
        createdTo: $to
      }
    ) {
      nodes {
        id
        name
        createdAt
      }
    }
  }
}
```

Variables:

```json
{
  "from": "2024-01-01T00:00:00Z",
  "to": "2024-02-01T00:00:00Z"
}
```

Filter by device:

```graphql
query {
  team {
    snaps(
      first: 10,
      filter: { deviceId: "device-id" }
    ) {
      nodes {
        id
        name
        sourceDeviceId
      }
    }
  }
}
```

Filter by app identifier:

```graphql
query {
  team {
    snaps(
      first: 10,
      filter: { deviceAppIdentifier: "my-app" }
    ) {
      nodes {
        id
        name
        sourceAppIdentifier
      }
    }
  }
}
```

Filter by name:

```graphql
query {
  team {
    snaps(
      first: 10,
      filter: { name: "car_detected" }
    ) {
      nodes {
        id
        name
      }
    }
  }
}
```

Filter by tags:

```graphql
query {
  team {
    snaps(
      first: 10,
      filter: { tags: ["night", "validation"] }
    ) {
      nodes {
        id
        name
        tags
      }
    }
  }
}
```

Filter by extras (custom metadata):

```graphql
query {
  team {
    snaps(
      first: 10,
      filter: { extras: { scene: "warehouse", lighting: "low" } }
    ) {
      nodes {
        id
        name
        extras
      }
    }
  }
}
```

Filter by file classification:

```graphql
query {
  team {
    snaps(
      first: 10,
      filter: { withFilesClassifiedAs: [IMAGE_COLOR, VIDEO] }
    ) {
      nodes {
        id
        name
        files {
          classification
        }
      }
    }
  }
}
```

Available file classifications:

 * `IMAGE_COLOR`: Color images
 * `IMAGE_STEREO_LEFT`: Left stereo image
 * `IMAGE_STEREO_RIGHT`: Right stereo image
 * `VIDEO`: Video files
 * `POINTCLOUD`: Point cloud data
 * `ANNOTATION`: Annotation files
 * `DISPARITY`: Disparity maps
 * `UNKNOWN_FILE`: Other file types

Combine multiple filters:

```graphql
query {
  team {
    snaps(
      first: 10,
      filter: {
        deviceId: "device-id",
        tags: ["validation"],
        createdFrom: "2024-01-01T00:00:00Z"
      }
    ) {
      nodes {
        id
        name
        tags
        createdAt
      }
    }
  }
}
```

Retrieve detailed information about a specific snap using its ID, including file download URLs.

```graphql
query($snapId: ID!) {
  team {
    snap(snapId: $snapId) {
      id
      name
      createdAt
      tags
      extras
      files {
        id
        name
        hash
        mimeType
        size
        presignedUrl
        classification
      }
      sourceDeviceId
      sourceSerialNumber
      sourceAppIdentifier
    }
  }
}
```

Variables:

```json
{
  "snapId": "snap-id-from-list"
}
```

Response example:

```json
{
  "data": {
    "team": {
      "snap": {
        "id": "snap-abc123",
        "name": "car_detected",
        "createdAt": "2024-01-15T10:30:00Z",
        "tags": ["validation", "warehouse"],
        "extras": { "scene": "warehouse", "lighting": "low" },
        "files": [
          {
            "id": "file-xyz789",
            "name": "image.jpg",
            "hash": "abc123...",
            "mimeType": "image/jpeg",
            "size": 524288,
            "presignedUrl": "https://storage.example.com/snap-abc123/image.jpg?signature=...",
            "classification": "IMAGE_COLOR"
          }
        ],
        "sourceDeviceId": "device-123",
        "sourceSerialNumber": "OAK123456",
        "sourceAppIdentifier": "detection-app"
      }
    }
  }
}
```

Key fields explained:

 * `presignedUrl`: Direct, time-limited URL to download the file. Use this URL to download files without authentication.
 * `hash`: File checksum for integrity verification
 * `mimeType`: MIME type of the file (e.g., `"image/jpeg"`, `"video/mp4"`)
 * `size`: File size in bytes
 * `sourceSerialNumber`: Device serial number that created the snap
 * `sourceAppIdentifier`: Application identifier that emitted the snap

Delete snaps using either their IDs or by applying filters. Deletion happens asynchronously as a background task.

> **Asynchronous Deletion**
> Snap deletion is not immediate. The API returns a `bgTaskId` that you can use to track deletion progress.

### Method 1: Delete by IDs

Delete specific snaps using their IDs:

```graphql
mutation DeleteSnapsByIds($ids: [ID!]!) {
  team {
    deleteSnapsByIds(ids: $ids) {
      status
      bgTaskId
    }
  }
}
```

Variables:

```json
{
  "ids": ["snap-id-1", "snap-id-2", "snap-id-3"]
}
```

Response:

```json
{
  "data": {
    "team": {
      "deleteSnapsByIds": {
        "status": "SUCCESS",
        "bgTaskId": "bg-task-abc123"
      }
    }
  }
}
```

### Method 2: Delete by Filter

Delete snaps matching specific criteria:

```graphql
mutation DeleteSnapsByFilter {
  team {
    deleteSnapsByFilter(
      filter: {
        deviceId: "device-id",
        createdFrom: "2024-01-01T00:00:00Z",
        createdTo: "2024-02-01T00:00:00Z",
        tags: ["test"]
      }
    ) {
      status
      bgTaskId
    }
  }
}
```

Available deletion filters:

 * `deviceId`: Delete snaps from a specific device
 * `deviceAppId`: Delete snaps from a specific app instance
 * `deviceAppIdentifier`: Delete snaps from apps with this identifier
 * `createdFrom`: Delete snaps created after this timestamp
 * `createdTo`: Delete snaps created before this timestamp
 * `name`: Delete snaps with this name
 * `tags`: Delete snaps with these tags
 * `extras`: Delete snaps with these custom metadata
 * `withFilesClassifiedAs`: Delete snaps containing files of this classification

### Check Deletion Status

Track deletion progress using the `bgTaskId`:

```graphql
query($bgTaskId: ID!) {
  team {
    bgTask(bgTaskId: $bgTaskId) {
      id
      state {
        deletedCount
        totalCount
      }
      createdAt
      completedAt
      failedAt
    }
  }
}
```

Variables:

```json
{
  "bgTaskId": "bg-task-id-from-deletion"
}
```

Response (in progress):

```json
{
  "data": {
    "team": {
      "bgTask": {
        "id": "bg-task-abc123",
        "state": {
          "deletedCount": 150,
          "totalCount": 500
        },
        "createdAt": "2024-01-15T11:00:00Z",
        "completedAt": null,
        "failedAt": null
      }
    }
  }
}
```

Response (completed):

```json
{
  "data": {
    "team": {
      "bgTask": {
        "id": "bg-task-abc123",
        "state": {
          "deletedCount": 500,
          "totalCount": 500
        },
        "createdAt": "2024-01-15T11:00:00Z",
        "completedAt": "2024-01-15T11:05:30Z",
        "failedAt": null
      }
    }
  }
}
```

### Status Values

The `status` field in deletion response can be:

 * `SUCCESS`: Deletion task created successfully
 * `IDS_NOT_FROM_TEAM`: One or more snap IDs don't belong to your team
 * `BG_TASK_LIMIT_REACHED`: Too many background tasks running, try again later

## Summary

In this guide, you learned how to:

 * List snaps with pagination and filtering
 * Retrieve detailed information about individual snaps
 * Download snap files using presigned URLs
 * Delete snaps by IDs or using filters
 * Track deletion progress via background tasks

> **Key Takeaways**
> * Use tags and extras for effective snap organization and searching
 * Leverage filters to query specific subsets of your data
 * Deletion is async - always check `bgTaskId` for progress
 * Presigned URLs are time-limited - download files promptly

## Next Steps

 * Check out [Snaps feature documentation](https://docs.luxonis.com/cloud/features/event-storage/snaps.md) to learn about managing
   snaps via the Luxonis Hub UI
 * Learn how to [send snaps from your applications](https://docs.luxonis.com/software-v3/depthai/tutorials/snaps.md) using DepthAI
 * Explore the [full schema reference](https://docs.luxonis.com/cloud/api/reference/control-api/schema.md) for all snap-related
   types and mutations
 * Discover more [automation guides](https://docs.luxonis.com/cloud/api/guides.md) for additional API integration examples
