# Acquisitions API

The Acquisitions API allows you to create, retrieve, update, and delete acquisition records. Acquisitions represent forensic data collections tied to cases, evidence items, and other related entities.

***

### Endpoints

| Method   | Path                  | Description                    |
| -------- | --------------------- | ------------------------------ |
| `GET`    | `/acquisitions`       | List all acquisitions          |
| `GET`    | `/acquisitions/:uuid` | Get a single acquisition       |
| `POST`   | `/acquisitions`       | Create a new acquisition       |
| `PATCH`  | `/acquisitions/:uuid` | Update an existing acquisition |
| `DELETE` | `/acquisitions/:uuid` | Delete an acquisition          |

***

### Data Model

Each acquisition object contains the following fields:

| Field            | Type   | Description                                         |
| ---------------- | ------ | --------------------------------------------------- |
| `acq_id`         | number | Internal acquisition ID                             |
| `uuid`           | string | Unique identifier                                   |
| `name`           | string | Acquisition name                                    |
| `format`         | string | Acquisition format (e.g., E01, DD, AD1)             |
| `type`           | string | Acquisition type                                    |
| `status`         | string | `"Active"` or `"Deleted"`                           |
| `size`           | number | Numeric size value                                  |
| `size_unit`      | string | Unit of size: `"B"`, `"KB"`, `"MB"`, `"GB"`, `"TB"` |
| `size_bytes`     | number | Calculated size in bytes                            |
| `size_gb`        | number | Calculated size in gigabytes                        |
| `description`    | string | Notes or description                                |
| `created_on`     | string | Timestamp when the record was created               |
| `updated_on`     | string | Timestamp when the record was last updated          |
| `acquire_date`   | string | Date the acquisition was performed (ISO 8601)       |
| `duration`       | number | Acquisition duration in seconds                     |
| `hashes`         | array  | Array of `{ type, hash }` objects                   |
| `storage`        | object | Linked storage location                             |
| `evidence`       | object | Linked evidence item                                |
| `case`           | object | Linked case                                         |
| `linked_contact` | object | Linked contact / custodian                          |
| `acquired_by`    | object | User who performed the acquisition                  |
| `location`       | object | Physical storage location                           |
| `custom_fields`  | array  | Custom field values                                 |

***

### GET /acquisitions

Retrieve a paginated list of acquisitions. Supports filtering by case, evidence, status, and date ranges.

#### Query Parameters

| Parameter         | Type   | Required | Description                                   |
| ----------------- | ------ | -------- | --------------------------------------------- |
| `uuid`            | string | No       | Filter by acquisition UUID                    |
| `acq_id`          | number | No       | Filter by acquisition ID                      |
| `evidence_uuid`   | string | No       | Filter by evidence UUID                       |
| `evidence_id`     | number | No       | Filter by evidence ID                         |
| `case_id`         | number | No       | Filter by case ID                             |
| `case_uuid`       | string | No       | Filter by case UUID                           |
| `status`          | string | No       | `"Active"` or `"Deleted"`                     |
| `created_after`   | string | No       | Records created on or after this date         |
| `created_before`  | string | No       | Records created on or before this date        |
| `acquired_after`  | string | No       | Acquisitions performed on or after this date  |
| `acquired_before` | string | No       | Acquisitions performed on or before this date |
| `updated_after`   | string | No       | Records updated on or after this date         |
| `updated_before`  | string | No       | Records updated on or before this date        |
| `page`            | number | No       | Page number (minimum: 1, default: 1)          |
| `page_size`       | number | No       | Results per page (1–1000, default: 1000)      |

#### Response

```json
{
  "data": [ ... ],
  "total": 42,
  "page_size": 25,
  "page": 1,
  "next_page": 2
}
```

The `next_page` field is `null` when there are no more pages.

#### Example: List All Acquisitions

```python
response = requests.get(
    f"{BASE_URL}/acquisitions",
    headers=HEADERS,
)

result = response.json()

for acq in result["data"]:
    print(f"{acq['uuid']} - {acq['name']} ({acq['size']} {acq['size_unit']})")

print(f"Total: {result['total']}")
```

#### Example: Filter by Case UUID with Pagination

```python
response = requests.get(
    f"{BASE_URL}/acquisitions",
    headers=HEADERS,
    params={
        "case_uuid": "abc-123-def-456",
        "status": "Active",
        "page_size": 25,
        "page": 1,
    },
)

result = response.json()
print(f"Page {result['page']} — showing {len(result['data'])} of {result['total']}")
```

#### Example: Filter by Date Range

```python
response = requests.get(
    f"{BASE_URL}/acquisitions",
    headers=HEADERS,
    params={
        "acquired_after": "2025-01-01",
        "acquired_before": "2025-12-31",
    },
)

for acq in response.json()["data"]:
    print(f"{acq['name']} — acquired {acq['acquire_date']}")
```

***

### GET /acquisitions/:uuid

Retrieve a single acquisition by UUID.

#### Example

```python
acquisition_uuid = "abc-123-def-456"

response = requests.get(
    f"{BASE_URL}/acquisitions/{acquisition_uuid}",
    headers=HEADERS,
)

acq = response.json()["data"][0]
print(f"Name: {acq['name']}")
print(f"Format: {acq['format']}")
print(f"Size: {acq['size']} {acq['size_unit']} ({acq['size_gb']} GB)")
print(f"Case: {acq['case']['case_number']}")

for h in acq["hashes"]:
    print(f"  {h['type']}: {h['hash']}")
```

***

### POST /acquisitions

Create a new acquisition.

#### Request Body

| Field                 | Type   | Required | Description                                     |
| --------------------- | ------ | -------- | ----------------------------------------------- |
| `name`                | string | **Yes**  | Acquisition name                                |
| `case_uuid`           | string | **Yes**  | UUID of the parent case                         |
| `uuid`                | string | No       | Custom UUID (auto-generated if omitted)         |
| `format`              | string | No       | Acquisition format (e.g., E01, DD)              |
| `type`                | string | No       | Acquisition type                                |
| `status`              | string | No       | `"Active"` or `"Deleted"`                       |
| `size`                | number | No       | Numeric size value                              |
| `size_unit`           | string | No       | `"B"`, `"KB"`, `"MB"`, `"GB"`, or `"TB"`        |
| `tool`                | string | No       | Tool used for acquisition                       |
| `tool_version`        | string | No       | Version of the acquisition tool                 |
| `description`         | string | No       | Notes or description                            |
| `acquire_date`        | string | No       | Date of acquisition (ISO 8601)                  |
| `duration`            | number | No       | Duration in seconds                             |
| `hash_1`              | string | No       | Primary hash value                              |
| `hash_1_type`         | string | No       | Primary hash algorithm (e.g., MD5, SHA1)        |
| `hash_2`              | string | No       | Secondary hash value                            |
| `hash_2_type`         | string | No       | Secondary hash algorithm                        |
| `storage_uuid`        | string | No       | UUID of the storage location                    |
| `evidence_uuid`       | string | No       | UUID of the parent evidence item                |
| `linked_contact_uuid` | string | No       | UUID of the linked contact / custodian          |
| `acquired_by_id`      | number | No       | User ID of the person who performed acquisition |
| `location_uuid`       | string | No       | UUID of the physical location                   |
| `custom_fields`       | array  | No       | Array of `{ field_id, value }` objects          |

#### Response

```json
{
  "data": { ... },
  "message": "Acquisition created successfully"
}
```

#### Example: Create a Basic Acquisition

```python
response = requests.post(
    f"{BASE_URL}/acquisitions",
    headers=HEADERS,
    json={
        "name": "Laptop-HDD-001",
        "case_uuid": "case-abc-123",
    },
)

result = response.json()
print(f"Created: {result['data']['uuid']}")
print(result["message"])
```

#### Example: Create with Full Details

```python
response = requests.post(
    f"{BASE_URL}/acquisitions",
    headers=HEADERS,
    json={
        "name": "Laptop-HDD-001-Full",
        "case_uuid": "case-abc-123",
        "evidence_uuid": "evidence-xyz-789",
        "format": "E01",
        "type": "Physical",
        "size": 256,
        "size_unit": "GB",
        "tool": "FTK Imager",
        "tool_version": "4.7.1",
        "description": "Full disk image of suspect laptop",
        "acquire_date": "2025-06-15T10:30:00Z",
        "duration": 7200,
        "hash_1": "d41d8cd98f00b204e9800998ecf8427e",
        "hash_1_type": "MD5",
        "hash_2": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
        "hash_2_type": "SHA1",
        "storage_uuid": "storage-def-456",
        "linked_contact_uuid": "contact-ghi-789",
        "acquired_by_id": 12,
        "custom_fields": [
            {"field_id": 1, "value": "Priority: High"},
            {"field_id": 2, "value": "Encrypted: No"},
        ],
    },
)

acq = response.json()["data"]
print(f"UUID: {acq['uuid']}")
print(f"Size: {acq['size_gb']} GB")
```

***

### PATCH /acquisitions/:uuid

Update an existing acquisition. Only include the fields you want to change.

#### Request Body

All fields from the create endpoint are accepted (except `case_uuid` is optional). Only provided fields will be updated.

#### Response

```json
{
  "data": { ... },
  "message": "Acquisition updated successfully"
}
```

#### Example: Update Name and Description

```python
acquisition_uuid = "abc-123-def-456"

response = requests.patch(
    f"{BASE_URL}/acquisitions/{acquisition_uuid}",
    headers=HEADERS,
    json={
        "name": "Laptop-HDD-001-Updated",
        "description": "Re-imaged with corrected write blocker settings",
    },
)

result = response.json()
print(result["message"])
print(f"Updated name: {result['data']['name']}")
```

#### Example: Update Hash Values

```python
acquisition_uuid = "abc-123-def-456"

response = requests.patch(
    f"{BASE_URL}/acquisitions/{acquisition_uuid}",
    headers=HEADERS,
    json={
        "hash_1": "e99a18c428cb38d5f260853678922e03",
        "hash_1_type": "MD5",
        "hash_2": "6dcd4ce23d88e2ee9568ba546c007c63d9131c1b",
        "hash_2_type": "SHA1",
    },
)

print(response.json()["message"])
```

#### Example: Update Custom Fields

```python
acquisition_uuid = "abc-123-def-456"

response = requests.patch(
    f"{BASE_URL}/acquisitions/{acquisition_uuid}",
    headers=HEADERS,
    json={
        "custom_fields": [
            {"field_id": 1, "value": "Priority: Low"},
        ],
    },
)

print(response.json()["message"])
```

***

### DELETE /acquisitions/:uuid

Permanently delete an acquisition by UUID.

#### Response

```json
{
  "data": { ... },
  "message": "Acquisition deleted successfully"
}
```

#### Example

```python
acquisition_uuid = "abc-123-def-456"

response = requests.delete(
    f"{BASE_URL}/acquisitions/{acquisition_uuid}",
    headers=HEADERS,
)

result = response.json()
print(result["message"])
print(f"Deleted: {result['data']['name']}")
```

***

### Error Handling

The API returns standard HTTP status codes:

| Code | Meaning                                    |
| ---- | ------------------------------------------ |
| 200  | Success                                    |
| 400  | Validation error (invalid parameters/body) |
| 401  | Unauthorized (missing or invalid API key)  |
| 500  | Internal server error                      |

Error responses include a `message` field. Validation errors also include an `errors` array with details.

```json
{
  "message": "Invalid request body",
  "errors": [
    {
      "code": "invalid_type",
      "expected": "string",
      "received": "undefined",
      "path": ["name"],
      "message": "Required"
    }
  ]
}
```

#### Example: Error Handling in Python

```python
response = requests.post(
    f"{BASE_URL}/acquisitions",
    headers=HEADERS,
    json={
        "description": "Missing required name and case_uuid",
    },
)

if response.status_code != 200:
    error = response.json()
    print(f"Error {response.status_code}: {error['message']}")
    if "errors" in error:
        for err in error["errors"]:
            print(f"  - {'.'.join(str(p) for p in err['path'])}: {err['message']}")
```

***

### Pagination

List responses are paginated. Use `page` and `page_size` to control pagination.

#### Example: Iterate Through All Pages

```python
def get_all_acquisitions(case_uuid):
    all_acquisitions = []
    page = 1

    while True:
        response = requests.get(
            f"{BASE_URL}/acquisitions",
            headers=HEADERS,
            params={
                "case_uuid": case_uuid,
                "page": page,
                "page_size": 100,
            },
        )

        result = response.json()
        all_acquisitions.extend(result["data"])

        if result["next_page"] is None:
            break

        page = result["next_page"]

    return all_acquisitions


acquisitions = get_all_acquisitions("case-abc-123")
print(f"Total acquisitions: {len(acquisitions)}")
```
