Overview
The Apps API manages applications displayed on Homarr boards. Apps represent external services, websites, or tools that users want to access from their dashboard.
Queries
all
Get all applications.
const apps = await api.app.all.query();
Authentication: Protected
Response: Array of apps ordered by name
App name (1-64 characters)
App description (max 512 characters)
App URL (must be valid URL or null)
URL to ping for status checks
getPaginated
Get apps with pagination.
const result = await api.app.getPaginated.query({
page: 1,
pageSize: 20,
search: "media",
});
Parameters:
Optional search query to filter by name
Response:
Total number of apps matching the search
search
Search apps by name.
const apps = await api.app.search.query({
query: "plex",
limit: 10,
});
Parameters:
selectable
Get apps suitable for selection in UI (minimal data).
const apps = await api.app.selectable.query();
Returns: Apps with only id, name, iconUrl, href, pingUrl, and description
byId
Get a single app by ID.
const app = await api.app.byId.query({ id: "app-id" });
Authentication: Public
Throws: NOT_FOUND if app doesn’t exist
byIds
Get multiple apps by IDs.
const apps = await api.app.byIds.query(["app-id-1", "app-id-2"]);
Authentication: Public
Mutations
create
Create a new application.
const result = await api.app.create.mutate({
name: "Plex",
description: "Media server",
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/svg/plex.svg",
href: "https://plex.example.com",
pingUrl: "https://plex.example.com/api/v2",
});
Permission Required: app-create
Parameters:
App name (1-64 characters, trimmed)
App description (max 512 characters)
URL to app icon (must be non-empty)
App URL - must be valid URL format, cannot use javascript: protocol
URL for status checks (must be HTTP/HTTPS)
Response:
ID of the newly created app
Validation:
href must be a valid URL or empty string (converted to null)
pingUrl must use HTTP or HTTPS protocol
javascript: URLs are blocked for security
createMany
Create multiple applications at once.
await api.app.createMany.mutate([
{
name: "Plex",
description: "Media server",
iconUrl: null, // Will auto-fetch icon
href: "https://plex.example.com",
},
{
name: "Sonarr",
description: "TV show management",
iconUrl: null,
href: "https://sonarr.example.com",
},
]);
Permission Required: app-create
Notes:
- If
iconUrl is null, Homarr will attempt to auto-fetch an icon based on the app name
- Falls back to default Homarr icon if no icon is found
- Must provide at least one app
update
Update an existing application.
await api.app.update.mutate({
id: "app-id",
name: "Plex Media Server",
description: "Updated description",
iconUrl: "https://new-icon-url.com/icon.svg",
href: "https://new-url.example.com",
pingUrl: "https://new-url.example.com/api",
});
Permission Required: app-modify-all
Throws: NOT_FOUND if app doesn’t exist
delete
Delete an application.
await api.app.delete.mutate({ id: "app-id" });
Permission Required: app-full-all
Deleting an app will remove it from all boards that reference it.
OpenAPI Endpoints
Some app endpoints are also exposed via REST API:
GET /api/apps
List all applications.
curl -X GET https://your-homarr.com/api/apps \
-H "Authorization: Bearer YOUR_API_KEY"
GET /api/apps/paginated
Get paginated apps.
curl -X GET "https://your-homarr.com/api/apps/paginated?page=1&pageSize=20" \
-H "Authorization: Bearer YOUR_API_KEY"
GET /api/apps/search
Search apps.
curl -X GET "https://your-homarr.com/api/apps/search?query=plex&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"
GET /api/apps/selectable
Get selectable apps (minimal data).
curl -X GET https://your-homarr.com/api/apps/selectable \
-H "Authorization: Bearer YOUR_API_KEY"
GET /api/apps/
Get app by ID.
curl -X GET https://your-homarr.com/api/apps/app-id-123 \
-H "Authorization: Bearer YOUR_API_KEY"
POST /api/apps
Create a new app.
curl -X POST https://your-homarr.com/api/apps \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Plex",
"description": "Media server",
"iconUrl": "https://icon-url.com/plex.svg",
"href": "https://plex.example.com",
"pingUrl": "https://plex.example.com/api"
}'
PATCH /api/apps/
Update an app.
curl -X PATCH https://your-homarr.com/api/apps/app-id-123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "app-id-123",
"name": "Updated Name",
"description": "Updated description",
"iconUrl": "https://new-icon.com/icon.svg",
"href": "https://new-url.com",
"pingUrl": "https://new-url.com/api"
}'
DELETE /api/apps/
Delete an app.
curl -X DELETE https://your-homarr.com/api/apps/app-id-123 \
-H "Authorization: Bearer YOUR_API_KEY"
Examples
Bulk Import Apps
const appsToCreate = [
{ name: "Plex", href: "https://plex.example.com", description: "Media Server" },
{ name: "Sonarr", href: "https://sonarr.example.com", description: "TV Shows" },
{ name: "Radarr", href: "https://radarr.example.com", description: "Movies" },
];
await api.app.createMany.mutate(
appsToCreate.map(app => ({
...app,
iconUrl: null, // Auto-fetch icons
}))
);
Search and Update
// Find apps matching a pattern
const mediaApps = await api.app.search.query({
query: "media",
limit: 50,
});
// Update all matching apps
for (const app of mediaApps) {
await api.app.update.mutate({
...app,
description: `${app.description} (Media Service)`,
});
}
Get App with Error Handling
try {
const app = await api.app.byId.query({ id: "app-id" });
console.log(`App: ${app.name}`);
} catch (error) {
if (error.code === 'NOT_FOUND') {
console.log('App does not exist');
} else {
console.error('Unexpected error:', error);
}
}