Admin API
Table of Contents
Why an Admin API Matters in E‑Commerce
The public API of your e‑commerce backend is for customers. The admin API is for staff, operators, and internal tools. It gives trusted users full control over the store.
You will already have many features in the project, such as products, users, orders, and background jobs. The admin API does not invent new business logic. It gives a controlled, powerful interface to manage that logic.
Typical admin users:
- Store owners
- Customer support agents
- Content managers
- Warehouse / logistics staff
- Finance / accounting tools
The goal of this chapter is to show how to expose existing features for internal use, protect them with strong authorization, and make them efficient and safe to use.
Some admin functions you will likely support:
- Manage users and their roles
- Manage products and categories
- Manage orders and refunds
- Manage inventory
- Inspect logs or background jobs status
- Trigger maintenance tasks such as reindexing or cache clearing
You should build the admin API on top of the same services, repositories, and entities used by the rest of the backend. The difference is in who can call it and how much power it gives them.
Designing Admin vs Public APIs
The admin API has different priorities than the public API.
Different audiences and priorities
Public API:
- Audience: customers, storefront, mobile apps, 3rd‑party integrations
- Focus: stability, backward compatibility, strict validation
- Security focus: protect customer data, avoid data leaks, rate limit
Admin API:
- Audience: trusted staff, internal tools
- Focus: completeness, power, visibility into internal data
- Security focus: strong authentication, strict authorization, auditing
Admin endpoints can be more verbose and detailed, because they are used by technical or trained users. For example:
- Public endpoint to get a product:
/products/{id}- Returns only fields needed for display: name, description, price, images
- Admin endpoint to get a product:
/admin/products/{id}- May include internal fields: cost_price, supplier_sku, is_featured, seo_meta, audit fields
Separate namespace
Use a clear path prefix for admin routes, for example:
/admin/.../api/admin/.../internal/admin/...
This helps:
- Apply different security policies
- Document the API clearly
- Avoid conflicts with public endpoints
Example structure:
| Area | Path example |
|---|---|
| Admin products | /admin/products, /admin/products/{id} |
| Admin categories | /admin/categories, /admin/categories/{id} |
| Admin users | /admin/users, /admin/users/{id} |
| Admin orders | /admin/orders, /admin/orders/{id} |
| Admin inventory | /admin/inventory/adjust |
| Admin jobs / tasks | /admin/jobs, /admin/jobs/{id} |
Different response models
You can use different models for the same resource in public vs admin APIs.
Example with FastAPI / Pydantic style models (language‑agnostic idea):
class ProductPublic(BaseModel):
id: int
name: str
description: str
price: Decimal
currency: str
image_urls: list[str]
class ProductAdmin(BaseModel):
id: int
name: str
description: str
price: Decimal
currency: str
image_urls: list[str]
# Admin‑only fields
cost_price: Decimal
margin_percentage: float
supplier_sku: str | None
is_active: bool
created_at: datetime
updated_at: datetime
last_purchased_at: datetime | NoneThis separation avoids accidental data leakage and keeps public responses simpler.
Versioning and stability
Public API changes can break clients. Admin UI and internal tools are under your control, so you can update them together with the API.
You still want to:
- Avoid random breaking changes
- Communicate changes to your internal users
- Consider a separate versioning for admin endpoints if you have many internal tools
Authentication and Authorization for Admin
Admin APIs hold the most sensitive capabilities of your system. Treat them as highly critical.
Strong authentication
Use a strong authentication method for admin access:
- JWT with admin roles
- OAuth 2.0 with scopes
- Session‑based auth tied to admin part of the app
- Multi‑factor authentication for admin accounts
Common pattern:
- User logs in via
/auth/loginor/admin/login. - Server returns a token with user claims that include roles/permissions.
- Admin endpoints verify the token and inspect roles.
Example JWT payload:
{
"sub": "user_123",
"email": "admin@example.com",
"roles": ["admin", "support"],
"permissions": [
"products:read",
"products:write",
"orders:read",
"orders:refund",
"users:read"
],
"iat": 1727400000,
"exp": 1727407200
}Admin endpoints would require specific roles or permissions, not just any authenticated user.
Rule: Never allow access to /admin endpoints using the same permissions as normal customer endpoints. Admin accounts must be authenticated and authorized separately and more strictly.
Role‑based and permission‑based checks
Use the concepts you learned in the Authorization section:
- Roles such as
admin,support,content_manager,warehouse. - Permissions such as
orders:refund,products:write,users:block.
Combine them in your checks:
- Only
admincan change other users' roles. supportcan edit orders but not change product prices.warehousecan update stock levels but not refund payments.
Example check in pseudocode:
def require_permission(user, permission: str):
if permission not in user.permissions:
raise ForbiddenError("Missing permission: " + permission)
@router.post("/admin/orders/{order_id}/refund")
def refund_order(order_id: int, current_user: User = Depends(get_current_user)):
require_permission(current_user, "orders:refund")
# perform refundNetwork and IP protections
In addition to authentication and authorization you can add network level defenses:
- Restrict admin API to VPN or corporate IP address ranges.
- Use separate domains, for example
admin-api.example.com. - Strong TLS configuration.
This is optional in small projects, but very important in real production setups.
Core Admin Endpoints
In the e‑commerce project you have several domains:
- Users
- Products
- Categories
- Orders
- Inventory
- Payments and refunds
- Background jobs
Admin API should provide full CRUD and management capabilities for these.
Admin product management
Some admin product endpoints:
| Method | Path | Description |
|---|---|---|
| GET | /admin/products | List products with filters |
| POST | /admin/products | Create a new product |
| GET | /admin/products/{id} | Get full product details |
| PUT | /admin/products/{id} | Replace product |
| PATCH | /admin/products/{id} | Partially update product |
| DELETE | /admin/products/{id} | Soft delete or archive a product |
Typical fields in admin request body:
- Public fields: name, description, price, currency, images
- Internal fields: cost_price, tax_rate, supplier info
- SEO fields: slug, meta_title, meta_description
- Catalog fields: category_ids, tags
- Status fields: is_active, is_featured, visibility_schedule
Example admin product creation payload:
{
"name": "Wireless Headphones X100",
"slug": "wireless-headphones-x100",
"description": "High quality wireless headphones...",
"price": 129.99,
"currency": "USD",
"cost_price": 80.00,
"tax_rate": 0.20,
"category_ids": [12, 34],
"tags": ["audio", "wireless", "headphones"],
"is_active": true,
"is_featured": false,
"image_urls": [
"https://cdn.example.com/images/x100-front.jpg",
"https://cdn.example.com/images/x100-side.jpg"
]
}Admin category management
Admin categories usually include:
- Name, slug
- Parent category for hierarchies
- Display order
- Visibility flag
Endoints:
/admin/categories/admin/categories/{id}
You can also add helper endpoints, for example:
/admin/categories/treeto get full category tree with nested children.
Admin user management
Admin users manage customer accounts:
| Method | Path | Description |
|---|---|---|
| GET | /admin/users | Search users by email, name, etc. |
| GET | /admin/users/{id} | Detailed user info |
| PATCH | /admin/users/{id} | Update profile, flags, notes |
| POST | /admin/users/{id}/block | Block a user account |
| POST | /admin/users/{id}/unblock | Unblock a user |
| GET | /admin/users/{id}/orders | List user orders |
Be careful with admin‑side operations that are dangerous:
- Changing a user's email
- Forcing password resets
- Deleting a user and their data
You should require stronger permissions for these and often keep an audit trail.
Admin order management
Admin orders are central to support and operations:
Common endpoints:
| Method | Path | Description |
|---|---|---|
| GET | /admin/orders | List orders with filters |
| GET | /admin/orders/{id} | Get full order with user and items |
| PATCH | /admin/orders/{id} | Update status, notes, metadata |
| POST | /admin/orders/{id}/refund | Create a refund |
| POST | /admin/orders/{id}/cancel | Cancel an order |
| POST | /admin/orders/{id}/resend-email | Resend confirmation |
Useful filters:
- Status:
pending,paid,shipped,cancelled,refunded - Date range:
created_from,created_to - Customer:
user_id,email - Financial:
min_total,max_total,payment_status
Example query:
GET /admin/orders?status=paid&created_from=2024-01-01&created_to=2024-01-31&page=1&limit=50
Example response shape:
{
"items": [
{
"id": 1001,
"user": {
"id": 23,
"email": "customer@example.com",
"full_name": "Jane Doe"
},
"status": "paid",
"payment_status": "captured",
"total_amount": 199.90,
"currency": "USD",
"created_at": "2024-01-12T10:34:56Z"
}
],
"page": 1,
"limit": 50,
"total_items": 132,
"total_pages": 3
}Admin inventory management
Inventory features connect to the "Inventory" chapter, but the admin UI and API will expose them.
Typical endpoints:
GET /admin/inventory/stock-levelswith filtersPOST /admin/inventory/adjustfor manual correctionsPOST /admin/inventory/bulk-adjustfor uploads from warehouse systemsGET /admin/inventory/movementsto see changes history
Adjustment example:
{
"product_id": 123,
"variant_id": 456,
"location_id": 1,
"delta": -2,
"reason": "Manual correction after damaged items",
"note": "2 items broken during packing"
}The backend would:
- Validate that the user has
inventory:adjustpermission. - Apply the stock change in a transaction.
- Record a stock movement entry for audit.
Admin Filters, Sorting, and Pagination
Admin users need to search and navigate large datasets, for example tens of thousands of orders or products. This is where good filtering and pagination design matters.
Common patterns for listing endpoints
You can define consistent parameters across admin listing endpoints:
| Parameter | Type | Purpose |
|---|---|---|
page | int | Page number, starting from 1 |
limit | int | Items per page, default such as 20 or 50 |
sort_by | str | Field to sort on, such as created_at |
sort_direction | str | asc or desc |
q | str | Free text search (email, name, SKU, etc.) |
You then add resource specific filters:
- For orders:
status,payment_status,user_id - For products:
category_id,is_active,min_price,max_price - For users:
email,is_blocked,created_from
Example orders list:
GET /admin/orders?page=2&limit=25&status=paid&sort_by=created_at&sort_direction=desc
Example products list:
GET /admin/products?page=1&limit=50&category_id=12&is_active=true&q=headphones
Response shape for paginated results
Use a consistent response model:
{
"items": [ /* list of resources */ ],
"page": 1,
"limit": 50,
"total_items": 1234,
"total_pages": 25
}
This makes admin UI components reusable. The frontend can use total_items and limit to build page navigation.
Safety considerations in filtering and sorting
When you accept sort_by or filter fields from the user:
- Validate that only allowed fields are used.
- Map them to real column names in code, not by inserting raw strings into SQL.
Example of safe mapping in pseudocode:
ALLOWED_SORT_FIELDS = {
"created_at": Order.created_at,
"total_amount": Order.total_amount,
"status": Order.status
}
if sort_by not in ALLOWED_SORT_FIELDS:
sort_column = Order.created_at
else:
sort_column = ALLOWED_SORT_FIELDS[sort_by]This prevents SQL injection vulnerabilities.
Rule: Never concatenate raw query parameters directly into SQL ORDER BY or WHERE clauses. Always validate fields against an allowlist and use query parameter binding.
Bulk Operations and Background Jobs
Admin tasks often involve many records at once. For example:
- Update prices for 500 products in a category.
- Mark 1000 orders as exported to a shipping provider.
- Recalculate all product search indexes.
Doing such operations in a single HTTP request that blocks until all work is done can:
- Take too long, leading to timeouts.
- Put a lot of load on the database and application server.
- Confuse the admin user if the UI freezes.
The solution is to combine admin endpoints with background processing (previously covered in the course).
Pattern: Start a job, then poll for status
A common design:
- Admin sends a request to start a bulk job.
- Backend validates the request and creates a job record with status
pending. - Backend pushes the job to a queue or background worker.
- Response returns the job ID immediately.
- Admin UI periodically calls a job status endpoint to display progress.
Example: bulk price update
Request:
POST /admin/products/bulk-update-price
{
"product_ids": [1, 2, 3, 4, 5],
"price_change_type": "percentage",
"value": 10.0,
"direction": "increase"
}Response:
{
"job_id": "job_abc123",
"status": "pending"
}Status endpoint:
GET /admin/jobs/job_abc123
{
"job_id": "job_abc123",
"type": "bulk_price_update",
"status": "running",
"created_at": "2024-02-01T10:00:00Z",
"started_at": "2024-02-01T10:00:02Z",
"finished_at": null,
"total_items": 5,
"processed_items": 3,
"failed_items": 0,
"errors": []
}
Admin UI can show a progress bar using processed_items / total_items.
Admin job types in an e‑commerce backend
Some useful job types:
bulk_price_updatebulk_product_activationbulk_category_assignmentorder_exportreport_generation(for example daily sales report)email_campaign_sync(send vouchers to inactive customers)rebuild_search_index
Each job type might have its own payload and logic, but the job status model can stay consistent.
Safety and auditing for bulk operations
Bulk operations are risky, so add protections:
- Require higher permissions for very powerful actions.
- Allow preview mode, for example show a list of affected products before execution.
- Require confirmation steps in UI ("Type CONFIRM to proceed").
- Write detailed logs of what was changed.
Example preview endpoint:
POST /admin/products/bulk-update-price/preview
{
"category_id": 10,
"price_change_type": "percentage",
"value": 15.0,
"direction": "decrease"
}Response:
{
"affected_count": 124,
"sample_products": [
{ "id": 1, "old_price": 100.0, "new_price": 85.0 },
{ "id": 2, "old_price": 59.99, "new_price": 50.99 }
]
}Auditing, Logging, and Safety
Admin APIs can change almost everything in your system. You should always be able to answer:
- Who did what
- When they did it
- What changed
Audit logs
Create an audit log for important admin actions:
- Creating, updating, deleting products
- Changing inventory levels
- Updating orders and processing refunds
- Changing user roles or blocking users
An audit log entry might contain:
idtimestampadmin_user_idaction(for exampleproduct.update,order.refund)resource_type(for exampleproduct,order,user)resource_idbefore(optional serialized snapshot of old data or selected fields)after(optional serialized snapshot of new data or selected fields)ip_addressanduser_agent
Example stored in JSON form:
{
"id": 1234,
"timestamp": "2024-03-10T12:34:56Z",
"admin_user_id": 42,
"action": "order.refund",
"resource_type": "order",
"resource_id": 1001,
"before": {
"status": "paid",
"refund_total": 0.0
},
"after": {
"status": "refunded",
"refund_total": 199.90
},
"ip_address": "203.0.113.10"
}You might expose audit logs through admin API endpoints:
GET /admin/audit-logsGET /admin/audit-logs/{id}
This helps investigations when something goes wrong.
Logging admin requests
For security and debugging:
- Log admin endpoint access, at least URL, method, user ID, response status.
- Be careful not to log passwords or secret data.
This helps you:
- Detect suspicious patterns, such as mass deletions or many failed attempts.
- Reconstruct what happened in incident investigations.
Safety controls
You can add safety controls around very sensitive admin operations:
- Require re‑authentication (password re‑entry) before:
- Changing other admin roles
- Rotating secrets or changing payment keys
- Use "soft delete" instead of physical deletion for important entities such as orders and products.
- Limit destructive operations such as "delete everything" in one click.
Rule: Never expose critical system secrets or full payment data through the admin API. Admins should see only what they need, such as last 4 digits of a card or masked tokens.
Designing a Simple Admin API for the Project
To make this concrete, here is a minimal but useful admin API design derived from earlier project chapters.
Example endpoint overview
| Area | Path example | Purpose |
|---|---|---|
| Products | GET /admin/products | List products with filters and pagination |
POST /admin/products | Create product | |
GET /admin/products/{id} | View product details | |
PATCH /admin/products/{id} | Edit product | |
POST /admin/products/{id}/images | Manage images (upload / reorder) | |
| Categories | GET /admin/categories | List categories |
POST /admin/categories | Create category | |
PATCH /admin/categories/{id} | Edit category | |
| Users | GET /admin/users | Search users |
GET /admin/users/{id} | View user details | |
POST /admin/users/{id}/block | Block user | |
| Orders | GET /admin/orders | List and filter orders |
GET /admin/orders/{id} | Full order details | |
POST /admin/orders/{id}/refund | Refund order | |
POST /admin/orders/{id}/cancel | Cancel order | |
| Inventory | GET /admin/inventory/stock-levels | View stock per product / variant |
POST /admin/inventory/adjust | Adjust stock | |
| Jobs | POST /admin/products/bulk-update-price | Start bulk price update job |
GET /admin/jobs/{id} | Check job status |
Example endpoint in more detail
Admin "get order" endpoint:
GET /admin/orders/{id}
Response:
{
"id": 1001,
"status": "paid",
"payment_status": "captured",
"created_at": "2024-01-12T10:34:56Z",
"updated_at": "2024-01-12T10:35:10Z",
"user": {
"id": 23,
"email": "customer@example.com",
"full_name": "Jane Doe",
"is_blocked": false
},
"items": [
{
"product_id": 123,
"variant_id": 456,
"name": "Wireless Headphones X100",
"sku": "X100-BLACK",
"unit_price": 99.95,
"quantity": 2,
"total_price": 199.90
}
],
"shipping_address": {
"full_name": "Jane Doe",
"address_line1": "123 Main St",
"city": "Springfield",
"country": "US",
"postal_code": "12345"
},
"billing_address": { /* ... */ },
"payment": {
"provider": "stripe",
"transaction_id": "pi_12345",
"paid_at": "2024-01-12T10:34:59Z"
},
"shipment": {
"carrier": "UPS",
"tracking_number": "1Z999AA10123456784",
"shipped_at": null
},
"notes": [
{
"id": 1,
"author": "admin@example.com",
"message": "Customer requested fast shipping.",
"created_at": "2024-01-12T10:35:05Z"
}
]
}This response is far more detailed than what the public API would expose, and it is designed for support agents that need to see everything about the order.
Summary
In the e‑commerce project, the admin API is:
- A separate namespace of powerful endpoints, such as
/admin/products,/admin/orders,/admin/users. - Protected by strong authentication and authorization, with roles and permissions.
- Designed for search, filtering, sorting, and pagination over large datasets.
- Integrated with background jobs for long‑running or bulk operations.
- Supported by audit logs and safety mechanisms to track and control changes.
Internally, it should reuse the same domain logic (services, repositories, models) as the rest of the backend. The difference is who can call it and what extra information and capabilities it exposes.
When you implement the Admin API for the project, start small:
- Identify the top 5 tasks admins must complete daily.
- Create endpoints for those tasks.
- Add filtering and pagination to make them usable at scale.
- Wrap sensitive actions in strong authorization checks and logging.
You can extend this foundation later with more admin features, including reports, dashboards, and integrations with external tools.
Views: 8
KAHIBARO