# Versioning Your API

All APIs register as version 1.0 by default, which means their endpoints are routed under `/umbraco/management/api/v1/`.

As projects evolve, adding new versions of your APIs sometimes becomes necessary. Multiple versions of the same API can co-exist to retain backward compatibility.

APIs are versioned using attribute annotation:

* `[ApiVersion]` attributes on the API controllers.
* `[MapToApiVersion]` attributes on the API controller actions.

{% hint style="info" %}
It is recommended to annotate *all* API controller actions, as well as the version 1.0 actions.
{% endhint %}

Using the API controller from the [Creating your own API article](/umbraco-cms/18.latest/extend-your-project/tutorials/creating-a-backoffice-api.md) as an example, we can add version 2.0 implementations of select actions:

{% code title="MyItemApiController.cs" %}

```csharp
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class MyItemApiController : ManagementApiControllerBase
{
    [HttpGet]
    [MapToApiVersion("1.0")]
    public IActionResult GetAllItems(int skip = 0, int take = 10)
    {
        // ...
    }

    [HttpGet("{id:guid}")]
    [MapToApiVersion("1.0")]
    public IActionResult GetItem(Guid id)
    {
        // ...
    }

    [HttpPost]
    [MapToApiVersion("1.0")]
    public IActionResult CreateItem(string value)
    {
        // ...
    }

    [HttpPut("{id:guid}")]
    [MapToApiVersion("1.0")]
    public IActionResult UpdateItem(Guid id, string value)
    {
        // ...
    }

    [HttpDelete("{id:guid}")]
    [MapToApiVersion("1.0")]
    public IActionResult DeleteItem(Guid id)
    {
        // ...
    }

    [HttpGet("{id:guid}")]
    [MapToApiVersion("2.0")]
    public IActionResult GetItemV2(Guid id)
    {
        MyItem? item = AllItems.FirstOrDefault(item => item.Id == id);

        return item is not null
            ? Ok(item)
            : OperationStatusResult(
                MyItemOperationStatus.NotFound,
                builder => NotFound(
                    builder
                        .WithTitle("The item was not found")
                        .WithDetail("The item with the given ID did not exist.")
                        .Build()
                )
            );
    }

    [HttpPost]
    [MapToApiVersion("2.0")]
    public IActionResult CreateItemV2(string value)
    {
        var newItem = new MyItem(value);
        AllItems.Add(newItem);
        return CreatedAtId<MyItemApiController>(
            ctrl => nameof(ctrl.GetItemV2),
            newItem.Id
        );
    }
}
```

{% endcode %}

Version 2.0 of the "get" and "create" endpoints - `GetItemV2` and `CreateItemV2` respectively, are added with the code above. The rest of the endpoints remain version 1.0 only.

{% hint style="info" %}
The version 2.0 endpoints are routed under `/umbraco/management/api/v2/`.
{% endhint %}

In the example above, the version 2.0 actions are added to the same API controller as their version 1.0 counterparts. If you prefer, they can be added to a new API controller instead. This will leave you with separate API controllers, one for each version of the API. See the examples below:

{% code title="MyItemApiController.cs" %}

```csharp
[ApiVersion("1.0")]
public class MyItemApiController : ManagementApiControllerBase
{
    [HttpGet]
    [MapToApiVersion("1.0")]
    public IActionResult GetAllItems(int skip = 0, int take = 10)
    {
        // ...
    }

    [HttpGet("{id:guid}")]
    [MapToApiVersion("1.0")]
    public IActionResult GetItem(Guid id)
    {
        // ...
    }

    [HttpPost]
    [MapToApiVersion("1.0")]
    public IActionResult CreateItem(string value)
    {
        // ...
    }

    [HttpPut("{id:guid}")]
    [MapToApiVersion("1.0")]
    public IActionResult UpdateItem(Guid id, string value)
    {
        // ...
    }

    [HttpDelete("{id:guid}")]
    [MapToApiVersion("1.0")]
    public IActionResult DeleteItem(Guid id)
    {
        // ...
    }
}
```

{% endcode %}

With the version 1.0 actions added in a controller sampled above, the version 2.0 actions are added in a new controller, as shown below.

{% code title="MyItemApiVersionTwoController.cs" %}

```csharp
[ApiVersion("2.0")]
public class MyItemApiVersionTwoController : ManagementApiControllerBase
{
    private static readonly List<MyItem> AllItems = Enumerable.Range(1, 100)
        .Select(i => new MyItem($"My V2 Item #{i}"))
        .ToList();

    [HttpGet("{id:guid}")]
    [MapToApiVersion("2.0")]
    public IActionResult GetItem(Guid id)
    {
        MyItem? item = AllItems.FirstOrDefault(item => item.Id == id);

        return item is not null
            ? Ok(item)
            : OperationStatusResult(
                MyItemOperationStatus.NotFound,
                builder => NotFound(
                    builder
                        .WithTitle("The item was not found")
                        .WithDetail("The item with the given ID did not exist.")
                        .Build()
                )
            );
    }

    [HttpPost]
    [MapToApiVersion("2.0")]
    public IActionResult CreateItem(string value)
    {
        var newItem = new MyItem(value);
        AllItems.Add(newItem);
        return CreatedAtId<MyItemApiVersionTwoController>(
            ctrl => nameof(ctrl.GetItem),
            newItem.Id
        );
    }
}
```

{% endcode %}

{% hint style="warning" %}
While perhaps tempting, do *not* name your API controller `V2` - e.g. `MyItemApiVersionV2`. Due to an upstream issue in the API versioning system, this will currently cause routing issues in certain scenarios.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.umbraco.com/umbraco-cms/18.latest/extend-your-project/tutorials/creating-a-backoffice-api/versioning-your-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
