# Custom Headless APIs

Custom Headless APIs have two primary use cases:

* For a fully headless solution, you will need custom APIs to serve catalogs, categories, and products to your client application.
* For any special requirements that are not covered by the out-of-the-box APIs.

The goal is to create endpoints that give you freedom of implementation while respecting our authentication.

## Prerequisites

* Out-of-the-box Headless API available (for example, by using our [Standalone Template](https://dev.ucommerce.net/readme/getting-started/standalone) as a starting point).
* Secrets are set up for your stores, and the URI whitelist is correctly configured in the API Access part of the administration interface. You can [learn about it here](https://dev.ucommerce.net/readme/headless).

## Creating the API Controller

* In your project, create a new Class and Inherit from `Ucommerce.Web.WebSite.Controllers.HeadlessControllerBase`

This will inherit our authentication, restricting its usage to only authenticated clients.

* Add a route to your controller. It can match the out-of-the-box route as follows:

```csharp
[Route("api/v1.0/products")]
```

* In your controller's constructor, you can inject any components you may need in your implementation. For example,

```csharp
private readonly IIndex<ProductSearchModel> _productIndex;

public ControllerName(IIndex<ProductSearchModel> productIndex)
{
    _productIndex = productIndex;
}
```

## Creating the method

* Create and annotate a new method with the HTTP method type and route.

```csharp
[HttpGet]
[Route("")]
```

* &#x20;For help with return types and choosing the right implementation details, [visit Microsoft's documentation.](https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types)
* Headless API authentication happens on a per-store basis. You can resolve the StoreId from the claim as follows:

```csharp
var storeGuid = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)
```

* Complete your implementation and return the results to your client.

## Complete example

For reference, here is a full controller example that will return products for a given Category:

```csharp
using System.Globalization;
using System.Security.Authentication;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
using Ucommerce.Extensions.Search.Abstractions;
using Ucommerce.Extensions.Search.Abstractions.Models.IndexModels;
using Ucommerce.Extensions.Search.Abstractions.Models.SearchModels;
using Ucommerce.Web.WebSite.Controllers;

namespace project.CustomHeadlessControllers;

[Route("api/v1.0/products")]
public class HeadlessProductController : HeadlessControllerBase
{
    private readonly IIndex<ProductSearchModel> _productIndex;

    public HeadlessProductController(IIndex<ProductSearchModel> productIndex)
    {
        _productIndex = productIndex;
    }

    [HttpGet("")]
    public async Task<ActionResult<YourResponseModel>> GetProducts(
        [FromQuery] Guid categoryId,
        [FromQuery] string cultureCode,
        CancellationToken token)
    {
        var storeGuid =
            Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? throw new AuthenticationException());
        var culture = new CultureInfo(cultureCode);
        var products = _productIndex.AsSearchable(culture).Where(x => x.CategoryIds.Contains(categoryId));

        // 
        var productsResponse = new YourResponseModel()
        {
            Products = YourMapProducts(products)
        };

        return productsResponse;
    }

    // YourMapProducts implementation
}
```

## Related Articles

{% content-ref url="" %}
[](https://dev.ucommerce.net/readme/headless)
{% endcontent-ref %}
