---
title: "Ajax in the backend"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:ajax-backend@main"
source: "ApiOverview/Backend/Ajax.rst"
rendered: "2026-09-24T12:36:55+00:00"
---

# Ajax in the backend {#ajax-backend}

An Ajax endpoint in the TYPO3 backend is usually implemented as a method in a
regular controller. The method receives a request object implementing the
`\Psr\Http\Message\ServerRequestInterface`, which allows to access all
aspects of the requests and returns an appropriate response in a normalized way.
This approach is standardized as [PSR-7](https://www.php-fig.org/psr/psr-7/).

## Create a controller {#ajax-backend-create-controller}

By convention, a controller is placed within the extension's `Controller/`
directory, optionally in a subdirectory. To have such controller, create a new
`ExampleController` in `Classes/Controller/ExampleController.php`
inside your extension.

The controller needs not that much logic right now. We create a method called
`doSomethingAction()` which will be our Ajax endpoint.

**EXT:my_extension/Classes/Controller/ExampleController.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final class ExampleController
{
  public function doSomethingAction(ServerRequestInterface $request): ResponseInterface
  {
    // TODO: return ResponseInterface
  }
}

```

In its current state, the method does nothing yet. We can add a very generic
handling that exponentiates an incoming number by 2. The incoming value will be
passed as a query string argument named `input`.

**EXT:my_extension/Classes/Controller/ExampleController.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final class ExampleController
{
  public function doSomethingAction(ServerRequestInterface $request): ResponseInterface
  {
    $input = $request->getQueryParams()['input']
        ?? throw new \InvalidArgumentException(
          'Please provide a number',
          1580585107,
        );

    $result = $input ** 2;

    // TODO: return ResponseInterface
  }
}

```

> [!NOTE]
> This is a really simple example. Something like this should not be used in
> production, as such a feature is available via JavaScript as well.

We have computed our result by using the [exponentiation operator](https://www.php.net/manual/en/language.operators.arithmetic.php), but we
do nothing with it yet. It is time to build a proper response:

**EXT:my_extension/Classes/Controller/ExampleController.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final class ExampleController
{
  public function __construct(
    private readonly ResponseFactoryInterface $responseFactory,
  ) {}

  public function doSomethingAction(ServerRequestInterface $request): ResponseInterface
  {
    $input = $request->getQueryParams()['input']
        ?? throw new \InvalidArgumentException(
          'Please provide a number',
          1580585107,
        );

    $result = $input ** 2;

    $response = $this->responseFactory->createResponse()
        ->withHeader('Content-Type', 'application/json; charset=utf-8');
    $response->getBody()->write(
      json_encode(['result' => $result], JSON_THROW_ON_ERROR),
    );
    return $response;
  }
}

```

## Register the endpoint {#ajax-backend-register-endpoint}

The endpoint must be registered as [route](https://docs.typo3.org/permalink/t3coreapi:backend-routing@main). Create a
file called [`Configuration/Backend/AjaxRoutes.php`](../../ExtensionArchitecture/FileStructure/Configuration/Backend/Index.md#file-extension-configuration-backend-ajaxroutes-php) in your extension. The
file basically just returns an array of route definitions. Every route in this
file will be exposed to JavaScript automatically. Let us register our endpoint
now:

**EXT:my_extension/Configuration/Backend/AjaxRoutes.php**

```php
<?php

use MyVendor\MyExtension\Controller\ExampleController;

return [
  'myextension_example_dosomething' => [
    'path' => '/my-extension/example/do-something',
    'target' => ExampleController::class . '::doSomethingAction',
  ],
];

```

The naming of the key `myextension_example_dosomething` and path
`/my-extension/example/do-something` are up to you, but should contain the
extension name, controller name and action name to avoid potential conflicts
with other existing routes.

> [!WARNING]
> **Attention**
>
> Flushing caches is mandatory after modifying any route definition.

## Protect the endpoint {#protect-ajax-endpoint}

> [!IMPORTANT]
> AJAX routes are **accessible to all authenticated backend users** by default
> and need proper permission checks in order to **avoid unauthorized access**.

Make sure to protect your endpoint against unauthorized access, if it performs
actions which are limited to authorized backend users only.

### Inherit access from backend module {#protect-ajax-endpoint-inherit-access-backend}

If your endpoint is part of a [backend module](https://docs.typo3.org/permalink/t3coreapi:backend-modules@main), you can
configure your endpoint to inherit access rights from this specific module by
using the configuration option `inheritAccessFromModule`:

**EXT:my_extension/Configuration/Backend/AjaxRoutes.php**

```php
<?php

use MyVendor\MyExtension\Controller\ExampleController;

return [
  'myextension_example_dosomething' => [
    'path' => '/my-extension/example/do-something',
    'target' => ExampleController::class . '::doSomethingAction',
    'inheritAccessFromModule' => 'my_module',
  ],
];

```

### Use permission checks on standalone endpoints {#protect-ajax-endpoint-permission-checks-standalone}

In case you're providing a standalone endpoint (that is, the endpoint is not
bound to a specific backend module), make sure to perform proper permission
checks on your own. You can use the
[backend user object](https://docs.typo3.org/permalink/t3coreapi:be-user-check@main) to perform various
authorization and permission checks on incoming requests.

## Use in Ajax {#ajax-backend-ajax}

Since the route is registered in `AjaxRoutes.php` it is exposed to
JavaScript now and stored in the global `TYPO3.settings.ajaxUrls` object
identified by the used key in the registration. In this example it is
`TYPO3.settings.ajaxUrls.myextension_example_dosomething`.

Now you are free to use the endpoint in any of your Ajax calls. To complete this
example, we will ask the server to compute our input and write the result into
the console.

**EXT:my_extension/Resources/Public/JavaScript/Calculate.js**

```javascript
import AjaxRequest from "@typo3/core/ajax/ajax-request.js";

// Generate a random number between 1 and 32
const randomNumber = Math.ceil(Math.random() * 32);
new AjaxRequest(TYPO3.settings.ajaxUrls.myextension_example_dosomething)
  .withQueryArguments({input: randomNumber})
  .get()
  .then(async function (response) {
    const resolved = await response.resolve();
    console.log(resolved.result);
  });

```

> [!NOTE]
> **See also**
>
> [Ajax request](https://docs.typo3.org/permalink/t3coreapi:ajax-request@main)
