/
/
/
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Music Assistant API Documentation</title>
7 <link rel="stylesheet" href="../resources/common.css">
8 <style>
9 body {
10 min-height: 100vh;
11 padding: 40px 20px;
12 }
13
14 .container {
15 max-width: 1100px;
16 margin: 0 auto;
17 overflow: hidden;
18 }
19
20 .header {
21 text-align: center;
22 padding: 48px 40px;
23 border-bottom: 1px solid var(--border);
24 }
25
26 .header h1 {
27 color: var(--fg);
28 font-size: 32px;
29 font-weight: 600;
30 letter-spacing: -0.5px;
31 margin-bottom: 8px;
32 }
33
34 .header .version {
35 color: var(--text-tertiary);
36 font-size: 14px;
37 }
38
39 .content {
40 padding: 40px;
41 }
42
43 .section {
44 margin-bottom: 48px;
45 }
46
47 .section:last-child {
48 margin-bottom: 0;
49 }
50
51 .section h2 {
52 color: var(--primary);
53 font-size: 24px;
54 font-weight: 600;
55 margin-bottom: 16px;
56 padding-bottom: 12px;
57 border-bottom: 2px solid var(--primary);
58 }
59
60 .section h3 {
61 color: var(--fg);
62 font-size: 18px;
63 font-weight: 600;
64 margin: 32px 0 16px 0;
65 }
66
67 .section p {
68 color: var(--text-secondary);
69 margin-bottom: 16px;
70 font-size: 15px;
71 }
72
73 .api-boxes {
74 display: grid;
75 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
76 gap: 20px;
77 margin: 24px 0;
78 }
79
80 .api-box {
81 background: var(--input-bg);
82 padding: 28px;
83 border-radius: 12px;
84 border: 1px solid var(--border);
85 transition: all 0.2s ease;
86 }
87
88 .api-box:hover {
89 transform: translateY(-2px);
90 box-shadow: 0 8px 24px var(--primary-glow);
91 border-color: var(--primary);
92 }
93
94 .api-box h4 {
95 color: var(--fg);
96 font-size: 18px;
97 font-weight: 600;
98 margin-bottom: 12px;
99 }
100
101 .api-box p {
102 color: var(--text-secondary);
103 font-size: 14px;
104 margin-bottom: 20px;
105 }
106
107 .api-box .btn {
108 display: inline-block;
109 background: var(--primary);
110 color: white;
111 padding: 12px 24px;
112 border-radius: 10px;
113 text-decoration: none;
114 font-weight: 600;
115 font-size: 14px;
116 transition: all 0.2s ease;
117 }
118
119 .api-box .btn:hover {
120 filter: brightness(1.1);
121 box-shadow: 0 4px 12px var(--primary-glow);
122 transform: translateY(-1px);
123 }
124
125 .code-block {
126 white-space: pre-wrap;
127 }
128
129 .code-block .comment {
130 color: var(--code-comment);
131 }
132
133 .code-block .string {
134 color: var(--code-string);
135 }
136
137 .code-block .keyword {
138 color: var(--code-keyword);
139 }
140
141 .highlight {
142 background: var(--input-focus-bg);
143 padding: 2px 6px;
144 border-radius: 4px;
145 font-weight: 500;
146 color: var(--primary);
147 }
148
149 code {
150 background: var(--input-bg);
151 color: var(--primary);
152 padding: 2px 6px;
153 border-radius: 4px;
154 font-size: 0.9em;
155 font-family: 'Monaco', 'Courier New', monospace;
156 }
157
158 .info-box {
159 background: var(--info-bg);
160 border: 1px solid var(--info-border);
161 border-left: 4px solid var(--primary);
162 padding: 20px;
163 margin: 20px 0;
164 border-radius: 10px;
165 }
166
167 .info-box strong {
168 color: var(--primary);
169 }
170
171 .events-list {
172 background: var(--input-bg);
173 padding: 24px;
174 border-radius: 10px;
175 border: 1px solid var(--border);
176 margin: 20px 0;
177 }
178
179 .events-list h4 {
180 color: var(--fg);
181 font-weight: 600;
182 margin-bottom: 16px;
183 font-size: 16px;
184 }
185
186 .events-list ul {
187 list-style: none;
188 padding-left: 0;
189 }
190
191 .events-list li {
192 padding: 10px 0;
193 border-bottom: 1px solid var(--border);
194 color: var(--text-secondary);
195 }
196
197 .events-list li:last-child {
198 border-bottom: none;
199 }
200
201 .events-list code {
202 background: var(--primary);
203 color: white;
204 padding: 4px 10px;
205 border-radius: 6px;
206 font-size: 13px;
207 font-weight: 500;
208 }
209
210 .client-links {
211 display: flex;
212 gap: 15px;
213 margin: 20px 0;
214 flex-wrap: wrap;
215 }
216
217 .client-link {
218 background: var(--input-bg);
219 color: var(--fg);
220 padding: 12px 24px;
221 border-radius: 10px;
222 text-decoration: none;
223 font-weight: 600;
224 font-size: 14px;
225 border: 1px solid var(--border);
226 transition: all 0.2s ease;
227 display: inline-flex;
228 align-items: center;
229 gap: 8px;
230 }
231
232 .client-link:hover {
233 background: var(--input-focus-bg);
234 border-color: var(--primary);
235 transform: translateY(-1px);
236 }
237
238 .footer {
239 background: var(--input-bg);
240 padding: 24px 40px;
241 text-align: center;
242 color: var(--text-secondary);
243 border-top: 1px solid var(--border);
244 font-size: 14px;
245 }
246
247 .footer a {
248 color: var(--primary);
249 text-decoration: none;
250 font-weight: 500;
251 }
252
253 .footer a:hover {
254 text-decoration: underline;
255 }
256
257 ul {
258 margin-left: 24px;
259 margin-bottom: 16px;
260 }
261
262 ul li {
263 color: var(--text-secondary);
264 margin-bottom: 8px;
265 }
266
267 .code-block .keyword {
268 color: var(--code-keyword);
269 }
270
271 .highlight {
272 background: var(--input-focus-bg);
273 padding: 2px 6px;
274 border-radius: 4px;
275 font-weight: 500;
276 color: var(--primary);
277 }
278
279 code {
280 background: var(--input-bg);
281 color: var(--primary);
282 padding: 2px 6px;
283 border-radius: 4px;
284 font-size: 0.9em;
285 font-family: 'Monaco', 'Courier New', monospace;
286 }
287
288 .info-box {
289 background: var(--info-bg);
290 border: 1px solid var(--info-border);
291 border-left: 4px solid var(--primary);
292 padding: 20px;
293 margin: 20px 0;
294 border-radius: 10px;
295 }
296
297 .info-box strong {
298 color: var(--primary);
299 }
300
301 .events-list {
302 background: var(--input-bg);
303 padding: 24px;
304 border-radius: 10px;
305 border: 1px solid var(--border);
306 margin: 20px 0;
307 }
308
309 .events-list h4 {
310 color: var(--fg);
311 font-weight: 600;
312 margin-bottom: 16px;
313 font-size: 16px;
314 }
315
316 .events-list ul {
317 list-style: none;
318 padding-left: 0;
319 }
320
321 .events-list li {
322 padding: 10px 0;
323 border-bottom: 1px solid var(--border);
324 color: var(--text-secondary);
325 }
326
327 .events-list li:last-child {
328 border-bottom: none;
329 }
330
331 .events-list code {
332 background: var(--primary);
333 color: white;
334 padding: 4px 10px;
335 border-radius: 6px;
336 font-size: 13px;
337 font-weight: 500;
338 }
339
340 .client-links {
341 display: flex;
342 gap: 15px;
343 margin: 20px 0;
344 flex-wrap: wrap;
345 }
346
347 .client-link {
348 background: var(--input-bg);
349 color: var(--fg);
350 padding: 12px 24px;
351 border-radius: 10px;
352 text-decoration: none;
353 font-weight: 600;
354 font-size: 14px;
355 border: 1px solid var(--border);
356 transition: all 0.2s ease;
357 display: inline-flex;
358 align-items: center;
359 gap: 8px;
360 }
361
362 .client-link:hover {
363 background: var(--input-focus-bg);
364 border-color: var(--primary);
365 transform: translateY(-1px);
366 }
367
368 .footer {
369 background: var(--input-bg);
370 padding: 24px 40px;
371 text-align: center;
372 color: var(--text-secondary);
373 border-top: 1px solid var(--border);
374 font-size: 14px;
375 }
376
377 .footer a {
378 color: var(--primary);
379 text-decoration: none;
380 font-weight: 500;
381 }
382
383 .footer a:hover {
384 text-decoration: underline;
385 }
386
387 ul {
388 margin-left: 24px;
389 margin-bottom: 16px;
390 }
391
392 ul li {
393 color: var(--text-secondary);
394 margin-bottom: 8px;
395 }
396 </style>
397</head>
398<body>
399 <div class="container">
400 <div class="header">
401 <div class="logo">
402 <img src="/logo.png" alt="Music Assistant">
403 </div>
404 <h1>Music Assistant API</h1>
405 <div class="version">Version {VERSION}</div>
406 </div>
407
408 <div class="content">
409 <div class="section">
410 <h2>Welcome</h2>
411 <p>
412 Music Assistant provides a powerful API to control your music library,
413 manage players, and stream audio. Whether you're building a custom interface,
414 integrating with home automation, or creating a music app, our API gives you
415 complete control.
416 </p>
417 <p>
418 This documentation will help you get started quickly with examples and best practices.
419 </p>
420 </div>
421
422 <div class="section">
423 <h2>API Documentation</h2>
424 <p>
425 Explore the Music Assistant API with our documentation tools:
426 </p>
427 <div class="api-boxes">
428 <div class="api-box">
429 <h4>ð Commands Reference</h4>
430 <p>Complete list of all available commands with parameters, descriptions, working curl examples, and interactive testing</p>
431 <a href="{BASE_URL}/api-docs/commands" class="btn">View Commands</a>
432 </div>
433 <div class="api-box">
434 <h4>ð Schemas Reference</h4>
435 <p>All data models and types with their properties, descriptions, and relationships</p>
436 <a href="{BASE_URL}/api-docs/schemas" class="btn">View Schemas</a>
437 </div>
438 <div class="api-box">
439 <h4>ð Swagger UI</h4>
440 <p>Interactive API explorer with OpenAPI specification and "Try it out" functionality</p>
441 <a href="{BASE_URL}/api-docs/swagger" class="btn">Open Swagger UI</a>
442 </div>
443 </div>
444 </div>
445
446 <div class="section">
447 <h2>Quick Start</h2>
448
449 <h3>WebSocket API (Recommended)</h3>
450 <p>
451 The WebSocket API provides <span class="highlight">real-time bidirectional communication</span>
452 and automatic event notifications. Perfect for applications that need live updates.
453 </p>
454 <div class="info-box">
455 <strong>Note:</strong> WebSocket messages require a <code>message_id</code> field to match requests with responses.
456 This allows multiple concurrent requests over the same connection.
457 </div>
458 <div class="code-block">
459<span class="comment"># Connect to WebSocket</span>
460ws://{SERVER_HOST}/ws
461
462<span class="comment"># Step 1: Authenticate (REQUIRED as first command)</span>
463{
464 <span class="string">"message_id"</span>: <span class="string">"auth-123"</span>,
465 <span class="string">"command"</span>: <span class="string">"auth"</span>,
466 <span class="string">"args"</span>: {
467 <span class="string">"token"</span>: <span class="string">"your_access_token"</span>
468 }
469}
470
471<span class="comment"># Auth response</span>
472{
473 <span class="string">"message_id"</span>: <span class="string">"auth-123"</span>,
474 <span class="string">"result"</span>: {
475 <span class="string">"authenticated"</span>: <span class="keyword">true</span>,
476 <span class="string">"user"</span>: {<span class="comment">...user info...</span>}
477 }
478}
479
480<span class="comment"># Step 2: Send commands (message_id is REQUIRED)</span>
481{
482 <span class="string">"message_id"</span>: <span class="string">"unique-id-123"</span>,
483 <span class="string">"command"</span>: <span class="string">"players/all"</span>,
484 <span class="string">"args"</span>: {}
485}
486
487<span class="comment"># Receive response</span>
488{
489 <span class="string">"message_id"</span>: <span class="string">"unique-id-123"</span>,
490 <span class="string">"result"</span>: [<span class="comment">...player data...</span>]
491}
492
493<span class="comment"># Receive automatic events</span>
494{
495 <span class="string">"event"</span>: <span class="string">"player_updated"</span>,
496 <span class="string">"data"</span>: {<span class="comment">...updated player...</span>}
497}
498 </div>
499
500 <h3>HTTP API (RPC)</h3>
501 <p>
502 The HTTP API provides a simple RPC-like interface for executing commands.
503 This allows you to call the same commands available via WebSocket over a simple HTTP POST endpoint.
504 Perfect for one-off commands without needing real-time updates.
505 </p>
506 <div class="info-box">
507 <strong>Note:</strong> The <code>message_id</code> field is <strong>optional</strong> for HTTP requests
508 since each HTTP request is isolated. The response returns the command result directly.
509 </div>
510 <div class="code-block">
511<span class="comment"># Get all players (requires authentication)</span>
512curl -X POST {BASE_URL}/api \
513 -H <span class="string">"Authorization: Bearer your_access_token"</span> \
514 -H <span class="string">"Content-Type: application/json"</span> \
515 -d <span class="string">'{
516 "command": "players/all",
517 "args": {}
518 }'</span>
519
520<span class="comment"># Play media on a player (requires authentication)</span>
521curl -X POST {BASE_URL}/api \
522 -H <span class="string">"Authorization: Bearer your_access_token"</span> \
523 -H <span class="string">"Content-Type: application/json"</span> \
524 -d <span class="string">'{
525 "command": "player_queues/play_media",
526 "args": {
527 "queue_id": "player_123",
528 "media": ["library://track/456"]
529 }
530 }'</span>
531
532<span class="comment"># Get server info (no authentication required)</span>
533curl {BASE_URL}/info
534 </div>
535 </div>
536
537 <div class="section">
538 <h2>WebSocket Events</h2>
539 <p>
540 When connected via WebSocket, you automatically receive real-time event notifications
541 for all state changes. No polling required!
542 </p>
543
544 <div class="events-list">
545 <h4>ð Player Events</h4>
546 <ul>
547 <li><code>player_added</code> - New player discovered</li>
548 <li><code>player_updated</code> - Player state changed</li>
549 <li><code>player_removed</code> - Player disconnected</li>
550 <li><code>player_config_updated</code> - Settings changed</li>
551 </ul>
552 </div>
553
554 <div class="events-list">
555 <h4>ðµ Queue Events</h4>
556 <ul>
557 <li><code>queue_added</code> - New queue created</li>
558 <li><code>queue_updated</code> - Queue state changed</li>
559 <li><code>queue_items_updated</code> - Content changed</li>
560 <li><code>queue_time_updated</code> - Playback position updated</li>
561 </ul>
562 </div>
563
564 <div class="events-list">
565 <h4>ð Library Events</h4>
566 <ul>
567 <li><code>media_item_added</code> - New media added</li>
568 <li><code>media_item_updated</code> - Metadata updated</li>
569 <li><code>media_item_deleted</code> - Media removed</li>
570 <li><code>media_item_played</code> - Playback started</li>
571 </ul>
572 </div>
573
574 <div class="events-list">
575 <h4>âï¸ System Events</h4>
576 <ul>
577 <li><code>providers_updated</code> - Provider status changed</li>
578 <li><code>tasks_updated</code> - Background tasks changed</li>
579 <li><code>music_sync_completed</code> - Music sync finished</li>
580 <li><code>application_shutdown</code> - Server shutting down</li>
581 </ul>
582 </div>
583 </div>
584
585 <div class="section">
586 <h2>Client Libraries</h2>
587 <p>
588 Don't want to implement the API from scratch? Use our official client libraries:
589 </p>
590
591 <h3>Python Client</h3>
592 <p>
593 Official Python client library with full type hints and async support:
594 </p>
595 <div class="code-block">
596<span class="comment"># Install</span>
597pip install music-assistant-client
598
599<span class="comment"># Usage</span>
600<span class="keyword">from</span> music_assistant_client <span class="keyword">import</span> MusicAssistantClient
601
602<span class="keyword">async with</span> MusicAssistantClient(<span class="string">"{SERVER_HOST}"</span>) <span class="keyword">as</span> client:
603 <span class="comment"># Get all players</span>
604 players = <span class="keyword">await</span> client.get_players()
605
606 <span class="comment"># Play media</span>
607 <span class="keyword">await</span> client.play_media(
608 queue_id=<span class="string">"player_123"</span>,
609 media=[<span class="string">"library://track/456"</span>]
610 )
611 </div>
612 <div class="client-links">
613 <a href="https://github.com/music-assistant/client" class="client-link">
614 ð¦ GitHub Repository
615 </a>
616 <a href="https://pypi.org/project/music-assistant-client/" class="client-link">
617 ð PyPI Package
618 </a>
619 </div>
620
621 <h3>TypeScript/JavaScript</h3>
622 <p>
623 Reference implementation in the Music Assistant frontend:
624 </p>
625 <div class="code-block">
626<span class="comment">// Example from frontend code</span>
627<span class="keyword">import</span> { MusicAssistantApi } <span class="keyword">from</span> <span class="string">'./api'</span>;
628
629<span class="keyword">const</span> api = <span class="keyword">new</span> MusicAssistantApi(<span class="string">'{SERVER_HOST}'</span>);
630
631<span class="comment">// Connect</span>
632<span class="keyword">await</span> api.connect();
633
634<span class="comment">// Subscribe to events</span>
635api.subscribe(<span class="string">'player_updated'</span>, (event) => {
636 console.log(<span class="string">'Player updated:'</span>, event.data);
637});
638
639<span class="comment">// Call commands</span>
640<span class="keyword">const</span> players = <span class="keyword">await</span> api.getPlayers();
641 </div>
642 <div class="client-links">
643 <a href="https://github.com/music-assistant/frontend/tree/main/src/plugins/api" class="client-link">
644 ð¦ Frontend API Code
645 </a>
646 </div>
647 <div class="info-box">
648 <strong>Coming Soon:</strong> A dedicated TypeScript client library is in development!
649 For now, you can use the frontend's API implementation as a reference.
650 </div>
651 </div>
652
653 <div class="section">
654 <h2>Best Practices</h2>
655 <p><strong>â Do:</strong></p>
656 <ul>
657 <li>Use WebSocket API for real-time applications</li>
658 <li>Handle connection drops and reconnect automatically</li>
659 <li>Subscribe to relevant events instead of polling</li>
660 <li>Use unique message IDs for WebSocket commands</li>
661 <li>Implement proper error handling</li>
662 </ul>
663 <p><strong>â Don't:</strong></p>
664 <ul>
665 <li>Poll the REST API frequently for updates (use WebSocket events instead)</li>
666 <li>Send commands without waiting for previous responses</li>
667 <li>Ignore error responses</li>
668 <li>Hardcode server URLs (make them configurable)</li>
669 </ul>
670 </div>
671
672 <div class="section">
673 <h2>Authentication</h2>
674 <p>
675 As of API Schema Version 28, <span class="highlight">authentication is now mandatory</span> for all API access
676 (except when accessed through Home Assistant Ingress).
677 </p>
678
679 <h3>Authentication Overview</h3>
680 <p>Music Assistant supports the following authentication methods:</p>
681 <ul>
682 <li><strong>Username/Password</strong> - Built-in authentication provider</li>
683 <li><strong>Home Assistant OAuth</strong> - OAuth flow for HA users (optional)</li>
684 <li><strong>Bearer Tokens</strong> - Token-based authentication for HTTP and WebSocket</li>
685 </ul>
686 <p>
687 When using tokens to automatically authenticate users, clients should be careful to validate that the server
688 ID for the server they are communicating with matches the ID observed when the user logged in explicitly. Otherwise,
689 there is a risk of sending tokens and attempting to authenticate with a different server that has the same local address
690 and port (<code>homeassistant.local:8095</code> for example).
691 </p>
692
693 <h3>HTTP Authentication Endpoints</h3>
694 <p>The following HTTP endpoints are available for authentication (no auth required):</p>
695 <div class="code-block">
696<span class="comment"># Get server info (includes onboard_done status)</span>
697GET {BASE_URL}/info
698
699<span class="comment"># Get available login providers</span>
700GET {BASE_URL}/auth/providers
701
702<span class="comment"># Login with credentials (built-in provider is default)</span>
703POST {BASE_URL}/auth/login
704{
705 <span class="string">"credentials"</span>: {
706 <span class="string">"username"</span>: <span class="string">"your_username"</span>,
707 <span class="string">"password"</span>: <span class="string">"your_password"</span>
708 }
709}
710
711<span class="comment"># Or specify a different provider (e.g., Home Assistant OAuth)</span>
712POST {BASE_URL}/auth/login
713{
714 <span class="string">"provider_id"</span>: <span class="string">"homeassistant"</span>,
715 <span class="string">"credentials"</span>: {<span class="comment">...provider-specific...</span>}
716}
717
718<span class="comment"># Response includes access token</span>
719{
720 <span class="string">"success"</span>: <span class="keyword">true</span>,
721 <span class="string">"token"</span>: <span class="string">"your_access_token"</span>,
722 <span class="string">"user"</span>: { <span class="comment">...user info...</span> }
723}
724
725<span class="comment"># First-time setup (only if no users exist)</span>
726POST {BASE_URL}/setup
727{
728 <span class="string">"username"</span>: <span class="string">"admin"</span>,
729 <span class="string">"password"</span>: <span class="string">"secure_password"</span>
730}
731 </div>
732
733 <h3>Using Bearer Tokens</h3>
734 <p>Once you have an access token, include it in all HTTP requests:</p>
735 <div class="code-block">
736curl -X POST {BASE_URL}/api \
737 -H <span class="string">"Authorization: Bearer your_access_token"</span> \
738 -H <span class="string">"Content-Type: application/json"</span> \
739 -d <span class="string">'{
740 "command": "players/all",
741 "args": {}
742 }'</span>
743 </div>
744
745 <h3>WebSocket Authentication</h3>
746 <p>
747 After establishing a WebSocket connection, you <strong>must</strong> send an
748 <code>auth</code> command as the first message:
749 </p>
750 <div class="code-block">
751<span class="comment"># Login with username and password...</span>
752{
753 <span class="string">"message_id"</span>: <span class="string">"auth-123"</span>,
754 <span class="string">"command"</span>: <span class="string">"auth"</span>,
755 <span class="string">"args"</span>: {
756 <span class="string">"username"</span>: <span class="string">"your_username"</span>
757 <span class="string">"password"</span>: <span class="string">"your_password"</span>
758 <span class="string">"device_name"</span>: <span class="string">"your_device_name"</span>
759 }
760}
761
762<span class="comment"># ...or use token from previous login</span>
763{
764 <span class="string">"message_id"</span>: <span class="string">"auth-123"</span>,
765 <span class="string">"command"</span>: <span class="string">"auth"</span>,
766 <span class="string">"args"</span>: {
767 <span class="string">"token"</span>: <span class="string">"your_access_token"</span>
768 }
769}
770
771<span class="comment"># Response on success</span>
772{
773 <span class="string">"message_id"</span>: <span class="string">"auth-123"</span>,
774 <span class="string">"result"</span>: {
775 <span class="string">"authenticated"</span>: <span class="keyword">true</span>,
776 <span class="string">"user"</span>: {
777 <span class="string">"user_id"</span>: <span class="string">"..."</span>,
778 <span class="string">"username"</span>: <span class="string">"your_username"</span>,
779 <span class="string">"role"</span>: <span class="string">"admin"</span>
780 }
781 }
782}
783 </div>
784
785 <div class="info-box">
786 <strong>Token Types:</strong>
787 <ul style="margin-top: 12px;">
788 <li><strong>Short-lived tokens:</strong> Created automatically during login. Expire after 30 days of inactivity but auto-renew on each use (sliding expiration window). Perfect for user sessions.</li>
789 <li><strong>Long-lived tokens:</strong> Created via <code>auth/token/create</code> command. Expire after 10 years with no auto-renewal. Intended for external integrations (Home Assistant, mobile apps, API access).</li>
790 </ul>
791 Use the <code>auth/tokens</code> and <code>auth/token/create</code> WebSocket commands to manage your tokens.
792 </div>
793
794 <h3>User Management Commands</h3>
795 <p>The following WebSocket commands are available for authentication management:</p>
796 <ul>
797 <li><code>auth/users</code> - List all users (requires the users.read scope)</li>
798 <li><code>auth/user</code> - Get user by ID (requires the users.read scope)</li>
799 <li><code>auth/user/create</code> - Create a new user (admin only)</li>
800 <li><code>auth/user/update</code> - Update user profile, password, or role (admin for other users)</li>
801 <li><code>auth/user/enable</code> - Enable user (admin only)</li>
802 <li><code>auth/user/disable</code> - Disable user (admin only)</li>
803 <li><code>auth/user/delete</code> - Delete user (admin only)</li>
804 <li><code>auth/tokens</code> - List your tokens</li>
805 <li><code>auth/token/create</code> - Create a new long-lived token</li>
806 <li><code>auth/token/revoke</code> - Revoke a token</li>
807 </ul>
808 <p>See the <a href="{BASE_URL}/api-docs/commands#auth" style="color: var(--primary); text-decoration: none; font-weight: 500;">Commands Reference</a> for detailed documentation of all auth commands.</p>
809 </div>
810
811 <div class="section">
812 <h2>Remote Access (WebRTC)</h2>
813 <p>
814 Music Assistant supports <span class="highlight">remote access via WebRTC</span>, enabling you to connect to your
815 Music Assistant instance from anywhere without port forwarding or VPN configuration.
816 </p>
817
818 <h3>How It Works</h3>
819 <p>
820 Remote access uses WebRTC technology to establish a secure, peer-to-peer connection between
821 your remote client (PWA) and your local Music Assistant server:
822 </p>
823 <ul>
824 <li><strong>WebRTC Data Channel:</strong> Establishes encrypted connection through NAT/firewalls</li>
825 <li><strong>Signaling Server:</strong> Cloud-based server coordinates connection setup</li>
826 <li><strong>Remote ID:</strong> Unique identifier (format: MA-XXXX-XXXX) to connect to your instance</li>
827 <li><strong>API Bridge:</strong> Remote commands work identically to local WebSocket API</li>
828 </ul>
829
830 <h3>Getting Your Remote ID</h3>
831 <p>Use the <code>remote_access/info</code> WebSocket command to get your Remote ID and connection status:</p>
832 <div class="code-block">
833<span class="comment"># Get remote access information</span>
834{
835 <span class="string">"message_id"</span>: <span class="string">"remote-123"</span>,
836 <span class="string">"command"</span>: <span class="string">"remote_access/info"</span>,
837 <span class="string">"args"</span>: {}
838}
839
840<span class="comment"># Response</span>
841{
842 <span class="string">"message_id"</span>: <span class="string">"remote-123"</span>,
843 <span class="string">"result"</span>: {
844 <span class="string">"enabled"</span>: <span class="keyword">true</span>,
845 <span class="string">"connected"</span>: <span class="keyword">true</span>,
846 <span class="string">"remote_id"</span>: <span class="string">"MA-K7G3-P2M4"</span>,
847 <span class="string">"signaling_url"</span>: <span class="string">"wss://signaling.music-assistant.io/ws"</span>
848 }
849}
850 </div>
851
852 <h3>Connecting Remotely</h3>
853 <p>To connect from outside your local network:</p>
854 <ol style="margin-left: 24px; color: var(--text-secondary);">
855 <li>Get your Remote ID from the <code>remote_access/info</code> command</li>
856 <li>Open the Music Assistant PWA from any device (https://app.music-assistant.io)</li>
857 <li>Enter your Remote ID when prompted</li>
858 <li>Authenticate with your username and password (or OAuth)</li>
859 <li>Full API access over encrypted WebRTC connection</li>
860 </ol>
861
862 <div class="info-box">
863 <strong>Availability Notice:</strong> Remote access is currently only available to users who:
864 <ul style="margin-top: 12px;">
865 <li>Have the Home Assistant integration configured</li>
866 <li>Possess an active <a href="https://www.nabucasa.com/" style="color: var(--primary); text-decoration: none; font-weight: 500;">Home Assistant Cloud</a> subscription</li>
867 </ul>
868 This limitation exists because remote access relies on cloud-based STUN/TURN servers provided by Home Assistant Cloud
869 to establish WebRTC connections through NAT/firewalls. These servers are expensive to host and are made available
870 as part of the Home Assistant Cloud service.
871 </div>
872
873 <h3>Security</h3>
874 <p>Remote access maintains the same security standards as local access:</p>
875 <ul>
876 <li><strong>End-to-end encryption:</strong> All data encrypted via WebRTC (DTLS/SRTP)</li>
877 <li><strong>Authentication required:</strong> Same login and token system as local access</li>
878 <li><strong>No data inspection:</strong> Signaling server cannot decrypt your commands or data</li>
879 <li><strong>Role-based access:</strong> Admin and user permissions work identically</li>
880 </ul>
881 </div>
882 </div>
883
884 <div class="footer">
885 <p>
886 Music Assistant {VERSION} â¢
887 <a href="https://music-assistant.io">music-assistant.io</a> â¢
888 <a href="https://github.com/music-assistant">GitHub</a>
889 </p>
890 </div>
891 </div>
892</body>
893</html>
894