> For the complete documentation index, see [llms.txt](https://teamleader-sdk.mcore-services.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://teamleader-sdk.mcore-services.dev/api-reference/projects/legacy-milestones.md).

# Legacy Milestones

Manage legacy project milestones in Teamleader Focus.

Milestones of the legacy project system — `milestones.*`.

```php
Teamleader::legacyMilestones()
```

|                          |                                                                       |
| ------------------------ | --------------------------------------------------------------------- |
| Class                    | `McoreServices\TeamleaderSDK\Resources\Projects\LegacyMilestones`     |
| Create / update / delete | ✓ / ✓ / ✓                                                             |
| Pagination               | `page_size` / `page_number`; no totals — a short page is the last one |

## Endpoints

* `milestones.close`
* `milestones.create`
* `milestones.delete`
* `milestones.info`
* `milestones.list`
* `milestones.open`
* `milestones.update`

## Filters

Passed as the first argument to `list()`. Any other key throws.

| Filter       | Description                                      |
| ------------ | ------------------------------------------------ |
| `due_after`  | Filter milestones due after date (Y-m-d format)  |
| `due_before` | Filter milestones due before date (Y-m-d format) |
| `ids`        | Array of milestone UUIDs to filter by            |
| `project_id` | Filter milestones by project UUID                |
| `status`     | Filter by milestone status (open, closed)        |
| `term`       | Search term - searches in milestone title        |

## Sorting

Pass `sort` (and optionally `sort_order`) in the options. Any other field throws.

| Field       | Description |
| ----------- | ----------- |
| `due_on`    | Due date    |
| `starts_on` | Start date  |

## Accepted values

Public constants on the class. Body fields and enum values outside these lists throw before the request is sent.

| Constant          | Values                                                                                                                                                          |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BILLING_METHODS` | `non_invoiceable`, `time_and_materials`, `fixed_price`                                                                                                          |
| `CREATE_FIELDS`   | `project_id`, `starts_on`, `due_on`, `name`, `description`, `responsible_user_id`, `depends_on`, `custom_fields`, `billing_method`, `budget`, `price`           |
| `CURRENCIES`      | `BAM`, `CAD`, `CHF`, `CLP`, `CNY`, `COP`, `CZK`, `DKK`, `EUR`, `GBP`, `INR`, `ISK`, `JPY`, `MAD`, `MXN`, `NOK`, `PEN`, `PLN`, `RON`, `SEK`, `TRY`, `USD`, `ZAR` |
| `STATUSES`        | `open`, `closed`                                                                                                                                                |
| `UPDATE_FIELDS`   | `starts_on`, `due_on`, `name`, `description`, `responsible_user_id`, `depends_on`, `propagate_date_changes`, `custom_fields`                                    |

## Methods

### `info()`

```php
info($id, $includes = null): array
```

Get detailed information about a specific milestone

* `$id` — Milestone UUID
* `$includes` — Not used for milestones

### `create()`

```php
create(array $data): array
```

Create a new milestone

* `$data` — Milestone data

**Throws** `InvalidArgumentException`

### `update()`

```php
update($id, array $data): array
```

Update an existing milestone

* `$id` — Milestone UUID
* `$data` — Data to update

**Throws** `InvalidArgumentException`

### `delete()`

```php
delete($id, ...$additionalParams): array
```

Delete a milestone

* `$id` — Milestone UUID
* `$additionalParams` — Not used for legacy milestones

### `close()`

```php
close(string $id): array
```

Close a milestone All open tasks will be closed, open meetings will remain open Closing the last open milestone will also close the project

* `$id` — Milestone UUID

### `open()`

```php
open(string $id): array
```

(Re)open a milestone If the milestone's project is closed, the project will be reopened

* `$id` — Milestone UUID

### `forProject()`

```php
forProject(string $projectId, array $options = []): array
```

Get all milestones for a specific project

* `$projectId` — Project UUID
* `$options` — Additional options (pagination, sorting)

### `list()`

```php
list(array $filters = [], array $options = []): array
```

List milestones

* `$filters` — ids, project\_id, status (open|closed), due\_before, due\_after, term
* `$options` — page\_size, page\_number, sort (due\_on|starts\_on), sort\_order

**Throws** `InvalidArgumentException` On an unknown filter key, option, value or sort field

### `getOpen()`

```php
getOpen(array $additionalFilters = [], array $options = []): array
```

Get open milestones

* `$additionalFilters` — Additional filters to apply
* `$options` — Additional options

### `getClosed()`

```php
getClosed(array $additionalFilters = [], array $options = []): array
```

Get closed milestones

* `$additionalFilters` — Additional filters to apply
* `$options` — Additional options

### `search()`

```php
search(string $term, array $options = []): array
```

Search milestones by term

* `$term` — Search term
* `$options` — Additional options

### `dueBefore()`

```php
dueBefore(string $date, array $additionalFilters = [], array $options = []): array
```

Get milestones due before a specific date

* `$date` — Date in Y-m-d format
* `$additionalFilters` — Additional filters
* `$options` — Additional options

### `dueAfter()`

```php
dueAfter(string $date, array $additionalFilters = [], array $options = []): array
```

Get milestones due after a specific date

* `$date` — Date in Y-m-d format
* `$additionalFilters` — Additional filters
* `$options` — Additional options

### `dueBetween()`

```php
dueBetween(string $startDate, string $endDate, array $additionalFilters = [], array $options = []): array
```

Get milestones due within a date range

* `$startDate` — Start date in Y-m-d format
* `$endDate` — End date in Y-m-d format
* `$additionalFilters` — Additional filters
* `$options` — Additional options

### `getAvailableBillingMethods()`

```php
getAvailableBillingMethods(): array
```

Get available billing methods

### `getAvailableStatuses()`

```php
getAvailableStatuses(): array
```

Get available status values

## Examples

Get all milestones:

```php
$milestones = Teamleader::legacyMilestones()->list();
```

Get milestones for a specific project:

```php
$milestones = Teamleader::legacyMilestones()->forProject('project-uuid');
```

Get only open milestones:

```php
$milestones = Teamleader::legacyMilestones()->list(['status' => 'open']);
```

Get a single milestone:

```php
$milestone = Teamleader::legacyMilestones()->info('milestone-uuid');
```

Create a new milestone:

```php
$milestone = Teamleader::legacyMilestones()->create([
                'project_id' => 'project-uuid',
                'name' => 'Initial setup',
                'due_on' => '2024-12-31',
                'responsible_user_id' => 'user-uuid',
                'billing_method' => 'time_and_materials'
            ]);
```

Update a milestone:

```php
$result = Teamleader::legacyMilestones()->update('milestone-uuid', [
                'name' => 'Updated name',
                'due_on' => '2024-12-31'
            ]);
```

Close a milestone:

```php
$result = Teamleader::legacyMilestones()->close('milestone-uuid');
```

Open/reopen a milestone:

```php
$result = Teamleader::legacyMilestones()->open('milestone-uuid');
```

Delete a milestone:

```php
$result = Teamleader::legacyMilestones()->delete('milestone-uuid');
```
