---
title: Using the Admin API | Shopware Community Hub
description: >-
  Learn how the Admin API works, how it is authenticated, and how it is used for
  shop-management and external integrations.
canonical_url: 'https://hub.shopware.com/learn/unit/using-the-admin-api'
---

# Using the Admin API

<LearningObjectives>

- Learn how authentication works for the Shopware Admin API using OAuth2.
- Understand the purpose and scope of the Admin API and how it differs from the Store API.
- Use common Admin API endpoints for shop management and external integration scenarios.
  
</LearningObjectives>

# Using the Admin API

Welcome to the comprehensive guide to the Shopware Admin API! This powerful interface gives you programmatic control over every aspect of your Shopware shop, from managing products and orders to configuring system settings and user permissions.

## Understanding the Admin API's Role

The Admin API serves as your command center for administrative operations. While the Store API handles customer-facing interactions, the Admin API provides comprehensive access to backend functions:

- **Product Management**: Create, update, delete, and manage product inventory
- **Order Operations**: Process orders, update statuses, and manage shipments
- **User Management**: Handle customers, administrators, and permissions
- **System Configuration**: Manage settings, plugins, and shop configuration
- **Bulk Operations**: Perform large-scale data operations efficiently
- **Automation**: Build tools that streamline your administrative workflow

## Authentication: Your Gateway to the API

Before accessing the Admin API, you need to establish secure authentication. Shopware uses OAuth2, providing robust security and fine-grained access control.

### Setting Up API Credentials

The first step is creating an integration in your Shopware admin panel:

1. Navigate to `Settings` → `Integrations` → `Add integration`
2. Provide a descriptive name for your integration
3. Configure appropriate permissions based on your needs
4. Save the integration and note your `Client ID` and `Client Secret`

### Obtaining Access Tokens

With your credentials in hand, you can now request an access token:

```bash
curl -X POST "https://your-shop.com/api/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'
```

A successful response will provide:

```json
{
  "token_type": "Bearer",
  "expires_in": 3600,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
}
```

For more information on OAuth2, refer to the [official documentation](https://shopware.stoplight.io/docs/admin-api/authentication).

### Using Your Access Token

Include the token in all subsequent API requests:

```bash
curl -X GET "https://your-shop.com/api/product" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"
```

### Example: Admin API Request in PHP

Let's look at a simple example showing how to fetch products via the **Admin API** using PHP:

```php
<?php declare(strict_types=1);

use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use RuntimeException;
use Throwable;

class MyAdminProductService
{
    public function __construct(
        private readonly HttpClientInterface $client    
    ) {
    }
    
    public function fetchActiveProducts(string $baseUrl, string $bearerToken): array
    {
        if (true === empty($baseUrl)) {
            throw new RuntimeException('Base URL is required.');        
        }
        
        if (true === empty($bearerToken)) {
            throw new RuntimeException('Bearer token is required.');
        }
        
        try {
            $response = $this->client->request('POST', $baseUrl . '/api/search/product', [
              'headers' => [
                  'Accept'           => 'application/json',
                  'Content-Type'     => 'application/json',
                  'Authorization'    => 'Bearer ' . $bearerToken,
              ],
              'json' => [
                  'limit'  => 3,
                  'filter' => [
                      [
                          'type'  => 'equals',
                          'field' => 'active',
                          'value' => true
                      ]
                  ]
              ]
            ]);
            
            if (Response::HTTP_OK !== $response->getStatusCode()) {
                throw new RuntimeException(
                    sprintf('Unexpected response status code: %s.', $response->getStatusCode())
                );
            }
            
            return $response->toArray();
        } catch(Throwable $e) {
            throw new RuntimeException(
                sprintf('Failed to fetch products: %s.', $e->getMessage())
            );
        }
    }
}
```

As you can see, this is very similar to the example in the previous learning unit. The difference is that the Admin API:

- Has the endpoint `/api/search/product` instead of `/store-api/product`.
- Uses the `Authorization` header with Bearer token instead of `sw-access-key` and `sw-context-token`.

## Core API Operations: Practical Examples

Now let's explore the essential operations you'll perform with the Admin API.

### Product Management

#### Retrieving Products

Get all products with pagination:

```bash
curl -X GET "https://your-shop.com/api/product?limit=10&page=1" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

Filter products by specific criteria:

```bash
curl -X GET "https://your-shop.com/api/product?filter[active]=1&filter[stock][gte]=10" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

#### Creating New Products

Add a new product to your catalog:

```bash
curl -X POST "https://your-shop.com/api/product" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Professional Developer T-Shirt",
    "productNumber": "DEV-TSHIRT-001",
    "description": "High-quality shirt for development professionals",
    "price": [
      {
        "currencyId": "CURRENCY_UUID",
        "net": 24.99,
        "gross": 29.99,
        "linked": false
      }
    ],
    "stock": 100,
    "taxId": "TAX_UUID"
  }'
```

**Note**: The `currencyId` and `taxId` are UUIDs specific to your shop configuration. You can retrieve these using the respective API endpoints.

#### Updating Products

Modify existing product information:

```bash
curl -X PATCH "https://your-shop.com/api/product/PRODUCT_UUID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Updated product description with enhanced features"
  }'
```

### Order Management

#### Retrieving Orders

Get recent orders with sorting:

```bash
curl -X GET "https://your-shop.com/api/order?sort=-orderDateTime&limit=20" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

Filter orders by status:

```bash
curl -X GET "https://your-shop.com/api/order?filter[stateMachineState][name]=open" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

#### Updating Order Status

Process orders by updating their status:

```bash
curl -X PATCH "https://your-shop.com/api/order/ORDER_UUID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stateId": "NEW_STATE_ID"
  }'
```

### Customer Management

#### Retrieving Customer Data

Get customer information with pagination:

```bash
curl -X GET "https://your-shop.com/api/customer?limit=50" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

#### Creating New Customers

Add customers to your system:

```bash
curl -X POST "https://your-shop.com/api/customer" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "salesChannelId": "SALES_CHANNEL_UUID",
    "customerNumber": "CUST-10001",
    "salutationId": "SALUTATION_UUID",
    "defaultPaymentMethodId": "PAYMENT_METHOD_UUID",
    "groupId": "CUSTOMER_GROUP_UUID",
    "languageId": "LANGUAGE_UUID",
    "firstName": "Jane",
    "lastName": "Developer",
    "email": "jane@example.com",
    "password": "securepassword123",
    "guest": false,
    "defaultBillingAddress": {
      "countryId": "COUNTRY_UUID",
      "salutationId": "SALUTATION_UUID",
      "firstName": "Jane",
      "lastName": "Developer",
      "street": "Example Street 1",
      "zipcode": "12345",
      "city": "Example City"
    },
    "defaultShippingAddress": {
      "countryId": "COUNTRY_UUID",
      "salutationId": "SALUTATION_UUID",
      "firstName": "Jane",
      "lastName": "Developer",
      "street": "Example Street 1",
      "zipcode": "12345",
      "city": "Example City"
    }
  }'
```

**Note**: Creating a customer usually requires more context than a simple product example. In most setups, fields such as `salesChannelId`, `customerNumber`, `defaultPaymentMethodId`, `languageId`, and nested default addresses are needed as well. The exact validation can vary depending on your Shopware version, configuration, and active extensions.

## Working with Custom Entities: ProductNotes Plugin

The Admin API automatically provides endpoints for custom entities created through plugins. Let's explore how this works with the AcademyProductNotes plugin.

### Understanding Custom Entity Endpoints

When you create custom entities like `academy_product_note`, Shopware automatically generates REST endpoints following the pattern:

```txt
/api/academy-product-note
```

### Managing Product Notes via API

#### Retrieving Product Notes

Get all product notes:

```bash
curl -X GET "https://your-shop.com/api/academy-product-note" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

Filter notes by product:

```bash
curl -X GET "https://your-shop.com/api/academy-product-note?filter[productId]=PRODUCT_UUID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

#### Creating New Product Notes

Add notes to products:

```bash
curl -X POST "https://your-shop.com/api/academy-product-note" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "productId": "PRODUCT_UUID",
    "userName": "Admin User",
    "note": "Product requires inventory review",
    "solved": false
  }'
```

#### Updating Product Notes

Mark notes as resolved:

```bash
curl -X PATCH "https://your-shop.com/api/academy-product-note/NOTE_UUID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "solved": true
  }'
```

#### Deleting Product Notes

Remove notes when they're no longer needed:

```bash
curl -X DELETE "https://your-shop.com/api/academy-product-note/NOTE_UUID" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Advanced Product Notes Operations

#### Retrieving Notes with Associations

Load notes with related product and user information:

```bash
curl -X GET "https://your-shop.com/api/academy-product-note?associations[product]=true&associations[user]=true" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

#### Bulk Operations on Notes

Update multiple notes simultaneously using the bulk sync endpoint:

```bash
curl -X POST "https://your-shop.com/api/_action/sync" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "update-notes": {
      "entity": "academy_product_note",
      "action": "upsert",
      "payload": [
        {
          "id": "NOTE_UUID_1",
          "solved": true
        },
        {
          "id": "NOTE_UUID_2",
          "solved": true
        }
      ]
    }
  }'
```

**Note**: Each bulk operation requires `entity`, `action`, and `payload` properties. The operation key name (e.g., `"update-notes"`) is used in the response to identify which entities were processed, making debugging easier. See the [Bulk Operations](#bulk-operations) section for more details on the structure and available actions.

## Advanced API Techniques

### Sophisticated Filtering and Searching

Combine multiple filter criteria for precise data retrieval:

```bash
# Find products with specific characteristics
curl -X GET "https://your-shop.com/api/product?filter[name][contains]=shirt&filter[stock][gte]=10&filter[active]=1" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"

# Search with multiple conditions
curl -X GET "https://your-shop.com/api/product?filter[categoryId]=CATEGORY_UUID&filter[price][gte]=20&sort=name" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

### Efficient Pagination

Handle large datasets with proper pagination:

```bash
curl -X GET "https://your-shop.com/api/product?page=1&limit=25" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

The response includes pagination metadata:

```json
{
  "data": [...],
  "meta": {
    "total": 150,
    "page": 1,
    "limit": 25
  }
}
```

### Bulk Operations

The Admin API supports bulk operations through the `/api/_action/sync` endpoint, allowing you to perform multiple write operations in a single request. This is more efficient than making individual API calls and ensures all operations are executed in a single transaction.

#### Understanding Bulk Payload Structure

A bulk request always contains a list of operations. Each operation defines:

- **`entity`**: The entity name in snake_case (e.g., `product`, `academy_product_note`, `customer`, `tax`)
- **`action`**: The operation type (`upsert` or `delete`)
- **`payload`**:
  - For `upsert` operations: An array of multiple records with their data
  - For `delete` operations: An array of objects containing the IDs to delete (for example `{ "id": "UUID" }`)

**Operation Keys for Debugging:**

Each operation can be given a unique key (e.g., `"write-tax"`, `"operation-1"`, `"update-products"`). This key is used in the API response to identify which entities were written in which operation, making it easier to debug and track the results of each operation. The key can be any string you choose.

**Multiple Entities in One Request:**

Within a single request, you can process different entities in batch. Each operation is independent and can target a different entity type, allowing you to efficiently handle complex data synchronization scenarios.

**Available Actions:**

- `upsert`: Create or update entities (creates if `id` doesn't exist, updates if it does). The payload contains full record data.
- `delete`: Delete entities. The payload contains objects with the entity IDs to delete.

#### Basic Structure Example

```json
{
  "operation-1": {
    "entity": "tax",
    "action": "upsert",
    "payload": [
      {
        "name": "tax-1",
        "taxRate": 16
      }
    ]
  }
}
```

#### Bulk Upsert Example

Use `upsert` to create or update entities. If an `id` is provided in the payload, the entity will be updated. If no `id` is provided, a new entity will be created:

```bash
curl -X POST "https://your-shop.com/api/_action/sync" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "upsert-products": {
      "entity": "product",
      "action": "upsert",
      "payload": [
        {
          "id": "EXISTING_PRODUCT_UUID",
          "stock": 150
        },
        {
          "name": "New Product",
          "productNumber": "PROD-NEW-001",
          "stock": 50,
          "price": [
            {
              "currencyId": "b7d2554b0ce847cd82f3ac9bd1c0dfca",
              "net": 15.99,
              "gross": 19.99,
              "linked": false
            }
          ],
          "taxId": "b7d2554b0ce847cd82f3ac9bd1c0dfca"
        }
      ]
    }
  }'
```

In this example, the first record (with `id`) will update an existing product, while the second record (without `id`) will create a new product.

#### Bulk Delete Example

Delete multiple entities. For delete operations, the payload contains an array of associative objects with an `id` field:

```bash
curl -X POST "https://your-shop.com/api/_action/sync" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "delete-products": {
      "entity": "product",
      "action": "delete",
      "payload": [
        {
          "id": "PRODUCT_UUID_1"
        },
        {
          "id": "PRODUCT_UUID_2"
        }
      ]
    }
  }'
```

#### Multiple Operations in One Request

You can combine different operations and entities in a single bulk request. Each operation uses a unique key (which can be any identifier) and will be referenced in the response for easier debugging:

```bash
curl -X POST "https://your-shop.com/api/_action/sync" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "update-products": {
      "entity": "product",
      "action": "upsert",
      "payload": [
        {
          "id": "PRODUCT_UUID_1",
          "stock": 50
        }
      ]
    },
    "create-customers": {
      "entity": "customer",
      "action": "upsert",
      "payload": [
        {
          "salesChannelId": "SALES_CHANNEL_UUID",
          "customerNumber": "CUST-10002",
          "salutationId": "SALUTATION_UUID",
          "defaultPaymentMethodId": "PAYMENT_METHOD_UUID",
          "groupId": "CUSTOMER_GROUP_UUID",
          "languageId": "LANGUAGE_UUID",
          "firstName": "John",
          "lastName": "Doe",
          "email": "john@example.com",
          "password": "securepassword",
          "guest": false,
          "defaultBillingAddress": {
            "countryId": "COUNTRY_UUID",
            "salutationId": "SALUTATION_UUID",
            "firstName": "John",
            "lastName": "Doe",
            "street": "Example Street 2",
            "zipcode": "54321",
            "city": "Example City"
          },
          "defaultShippingAddress": {
            "countryId": "COUNTRY_UUID",
            "salutationId": "SALUTATION_UUID",
            "firstName": "John",
            "lastName": "Doe",
            "street": "Example Street 2",
            "zipcode": "54321",
            "city": "Example City"
          }
        }
      ]
    },
    "delete-notes": {
      "entity": "academy_product_note",
      "action": "delete",
      "payload": [
        {
          "id": "NOTE_UUID_1"
        },
        {
          "id": "NOTE_UUID_2"
        }
      ]
    }
  }'
```

**Important Notes:**

- All operations in a bulk request are executed in a single transaction
- If any operation fails, the entire transaction is rolled back
- The operation key name (e.g., `"update-products"`, `"operation-1"`, `"1234-test"`) is used in the response to identify which entities were written in which operation, making debugging easier
- Entity names must be in snake_case (e.g., `academy_product_note` not `academyProductNote` or `academy-product-note`)
- For `upsert` operations, the payload contains full record data. If an `id` is present, the entity will be updated; if not, it will be created
- For `delete` operations, the payload contains an array of objects with `id` fields, not a plain array of strings
- Different entities can be processed in the same request, with each operation targeting a different entity type

For more details, see the [Shopware Admin API Bulk Payloads documentation](https://shopware.stoplight.io/docs/admin-api/faf8f8e4e13a0-bulk-payloads).

## Best Practices for Production Use

### Security Considerations

- **Secure credential storage**: Never expose client secrets in client-side code
- **HTTPS enforcement**: Use secure connections for all API communications
- **Token management**: Implement proper token storage and refresh mechanisms
- **Permission scoping**: Set appropriate permissions for your integrations

### Performance Optimization

- **Implement pagination**: Handle large datasets efficiently
- **Use caching**: Cache frequently accessed data when appropriate
- **Batch operations**: Group related operations when possible
- **Rate limiting**: Respect API limits and implement backoff strategies

### Testing and Development

Always test in a development environment first:

```bash
# Verify endpoint availability
curl -X GET "https://your-dev-shop.com/api/product" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"

# Check response headers for rate limiting information
curl -I "https://your-shop.com/api/product" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Real-World Implementation Examples

### Automated Inventory Management

Create a script for daily inventory reports:

```bash
#!/bin/bash
# Generate low stock report
curl -X GET "https://your-shop.com/api/product?filter[stock][lte]=10" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq '.data[] | {name: .attributes.name, stock: .attributes.stock}'
```

### Order Processing Automation

Automate order status updates:

```bash
# Process pending orders
curl -X GET "https://your-shop.com/api/order?filter[stateMachineState][name]=pending" \
  -H "Authorization: Bearer $TOKEN" | jq -r '.data[].id' | while read order_id; do
  curl -X PATCH "https://your-shop.com/api/order/$order_id" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"stateId": "PROCESSING_STATE_ID"}'
done
```

### Product Notes Integration

Automate note management for products:

```bash
# Get all unsolved notes for review
curl -X GET "https://your-shop.com/api/academy-product-note?filter[solved]=false" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq '.data[] | {productId: .attributes.productId, note: .attributes.note}'
```

## Common Challenges and Solutions

### Authentication Issues

- **Token expiration**: Implement automatic token refresh
- **Permission errors**: Verify integration permissions match your requirements
- **Rate limiting**: Implement exponential backoff for failed requests

### Data Handling

- **Large datasets**: Use pagination and filtering to manage data volume
- **Complex queries**: Break down complex operations into smaller, manageable requests
- **Error handling**: Always implement proper error handling for production applications

## Next Steps and Advanced Topics

With the fundamentals mastered, consider exploring:

- **Custom API endpoints**: Extend the API with your own endpoints
- **Webhook integration**: Implement real-time notifications
- **External system integration**: Connect with ERP, CRM, or other business systems
- **Mobile applications**: Build admin tools for mobile devices
- **Advanced automation**: Create sophisticated workflows and business logic

## Resources and Tools

- **API Documentation**: [https://shopware.stoplight.io/docs/admin-api](https://shopware.stoplight.io/docs/admin-api/twpxvnspkg3yu-quick-start-guide)
- **Testing Tools**: Postman, Insomnia, or custom scripts
- **Community Resources**: Shopware developer forums and documentation
- **Development Tools**: Use the generated API client for efficient development

## Summary

Well done! In this learning unit, you learned:

- What the Admin API is responsible for and how it differs from the Store API.
- How Admin API authentication works using OAuth2 and bearer tokens.
- How to access and manage core entities such as products, orders, customers, and configuration data.
- How custom entities created by plugins are automatically exposed through the Admin API.
- How bulk operations work using the sync endpoint efficiently write or delete data.
- Which best practices to follow regarding security, permissions, and performance.

With this knowledge, you can safely use the Admin API for shop management and external integrations without mixing it up with Store API concepts.
