Meuspace API Reference
Build your own frontend on top of your sovereign space. The Meuspace API lets you manage your server, publish content, and reach your audience straight from your own domain.
Browse documentation
Introduction
The Meuspace API is a REST interface organised around five areas of your space: Server, Content, Collections, Templates, and Audience. Every request is scoped to your own server, so your data never leaves your domain.
Server
Provision details, health, storage and custom domains.
Content
Play and browse the media and posts on your space.
Collections
Group content into releases, albums and playlists.
Templates
Reusable blueprints for the content you publish.
Audience
Subscribers, broadcasts and engagement statistics.
Base URL
All endpoints are relative to the following base URL. Requests must be made over HTTPS.
https://api.meuspace.com/v1
| Environment | Base URL | Notes |
|---|---|---|
| Production | https://api.meuspace.com/v1 | Live data, real payouts. |
| Sandbox | https://api.sandbox.meuspace.com/v1 | Dummy data, safe to experiment. |
Authentication
Authenticate every request with a Bearer token. API keys are issued for your space and can be revoked at any time; a revoked or disabled key stops working immediately. Treat keys like passwords and never expose them in client-side code.
Authorization: Bearer ms_live_xxxxxxxxxxxxxxxx
If you hold a credential (username and password) you can exchange it for a short-lived Bearer token instead of keeping a long-lived key around:
curl -X POST https://api.meuspace.com/v1/auth/login \
-H "Content-Type: application/json" \
-d '{ "username": "mxapi_xxxxxxxx", "password": "xxxxxxxx" }'
The response carries an access_token; send it as Authorization: Bearer <token>. Tokens expire, so request a new one when they do. The token carries your credential's roles and its allowed origins.
Requests without a valid token are rejected with 401 unauthorized. A credential that is valid but not allowed to reach the resource is rejected with 403 forbidden.
Browser-facing routes. The browser-facing route groups (server, collection, content, audience, template) additionally require an Origin (or X-Meusx-Origin) header whose value is one of the origins you added to your credential. A missing or unlisted origin is rejected with 403 forbidden.
Keep credentials and keys server-side only. API keys are long-lived secrets with no built-in expiry, so never embed them in browser code or ship them with a client application. Prefer the short-lived token for anything that runs in a browser, and rotate or revoke a key immediately if it is ever exposed.
Quickstart
Make your first call by fetching your server profile.
# Store your key once
export MEUSPACE_API_KEY="ms_live_xxxxxxxxxxxxxxxx"
# Verify your server
curl https://api.meuspace.com/v1/server \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
{
"id": "srv_8f3k2m",
"handle": "yourname",
"domain": "yourname.meuspace.com",
"status": "active",
"region": "us-east-1",
"created_at": "2026-01-14T09:32:11Z"
}
Server
Manage the machine that powers your space.
GET
/v1/server
Returns the profile of the server associated with your API key.
{
"id": "srv_8f3k2m",
"handle": "yourname",
"domain": "yourname.meuspace.com",
"status": "active",
"region": "us-east-1",
"plan": "studio",
"created_at": "2026-01-14T09:32:11Z"
}
GET
/v1/server/status
Real-time health, storage usage and bandwidth for your server.
{
"status": "operational",
"uptime_seconds": 4823910,
"storage": { "used_gb": 128.4, "limit_gb": 1024 },
"bandwidth": { "used_gb": 742.1, "limit_gb": 5120 }
}
GET
/v1/server/profile
The public profile of your server: identity and presentation, published content and collections, the pinned item, follower count, Nostr key and feed configuration.
{
"bannerPath": "https://cdn.meuspace.com/banner.jpg",
"avatarPath": "https://cdn.meuspace.com/avatar.jpg",
"artisticName": "Your Name",
"bio": "Producer and DJ.",
"isLive": false,
"contents": [
{
"publicId": "cnt_9x8y7z",
"title": "Live from the studio",
"versions": [
{
"proprietaryId": null,
"items": [
{
"publicId": "0035a3b2-475d-49bd-bb99-30ccb39c8948",
"title": "Studio Time",
"description": "Wednesday practice session",
"status": "UPLOADED",
"partSequenceNumber": 5,
"thumbPath": "https://cdn.meuspace.com/public/default_video_thumb.png",
"created": "2026-09-30T17:25:39.208"
}
]
}
]
}
],
"collections": [
{
"publicId": "col_1a2b3c",
"title": "Studio Sessions",
"artworkPath": "https://cdn.meuspace.com/art.jpg",
"type": "BundleRelease",
"created": "2026-01-14T09:32:11Z",
"proprietaryIds": [
{ "namespace": "MEUSTREAMS:ReleaseReference", "value": "196589201234" }
]
}
],
"pinnedContent": {
"publicId": "8218cca4-7597-43c0-ad32-149548e2b3a1",
"title": "Testing a New Vibe",
"thumb": "https://cdn.meuspace.com/public/default_video_thumb.png",
"artistAvatar": "https://cdn.meuspace.com/avatar.jpg",
"artistName": "Your Name",
"nViews": 6
},
"nFollowers": 1284,
"publicKey": "2a305a9dbf667137bb0b07bfc68161ee402bf0a1e54e1d6fdfc779950bfefc3d",
"feed": {
"published": false,
"layoutId": "layout-1"
}
}
GET
/v1/server/feed
The feed configuration of your server: the layout it renders and whether the feed is published.
{
"layout": "layout-1",
"published": false,
"pinned_content_id": null
}
GET
/v1/server/domains
List every domain attached to your server, including the default <you>.meuspace.com.
{
"data": [
{ "id": "dom_1a2b3c", "hostname": "yourname.com", "verified": true, "primary": true },
{ "id": "dom_4d5e6f", "hostname": "yourname.meuspace.com", "verified": true, "primary": false }
]
}
POST
/v1/server/domains
Attach a custom domain. You will receive DNS records to verify ownership.
curl -X POST https://api.meuspace.com/v1/server/domains \
-H "Authorization: Bearer $MEUSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "hostname": "yoursite.com" }'
PATCH
/v1/server
Update server-level settings such as the display handle or primary domain.
| Field | Type | Description |
|---|---|---|
| handle | string optional | Your public handle, used in your default URL. |
| primary_domain | string optional | Hostname to serve as the canonical domain. |
| timezone | string optional | IANA timezone, e.g. America/Sao_Paulo. |
POST
/v1/server/verify-domain
Verify ownership of an attached domain. Your server checks the DNS records you created and marks the domain verified when they match.
curl -X POST https://api.meuspace.com/v1/server/verify-domain \
-H "Authorization: Bearer $MEUSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "hostname": "yoursite.com" }'
{
"hostname": "yoursite.com",
"verified": true,
"records": [
{ "type": "CNAME", "name": "yoursite.com", "value": "yourname.meuspace.com" }
]
}
Content
Play and browse everything on your space.
GET
/v1/content/{contentId}
Play information for a content: the server it streams from and its parts, ready to hand to a player.
{
"info": {
"serverId": "srv_8f3k2m",
"parts": [
{
"contentId": "cnt_9x8y7z",
"title": "Live from the studio",
"status": "RECORDED",
"duration": 1864,
"partSequenceNumber": 1,
"artwork": "https://cdn.meuspace.com/art.jpg",
"previewThumb": "https://cdn.meuspace.com/thumb.jpg",
"isLive": false,
"serverId": "srv_8f3k2m",
"contributors": [
{ "publicId": "art_1a2b3c", "name": "Your Name", "role": "artist", "avatar": "https://cdn.meuspace.com/avatar.jpg", "nsubs": 1284, "publicKey": "2a305a9d..." }
],
"versions": [
{ "publicId": "ver_1a2b3c", "itemId": "item_1a2b3c" }
]
}
]
}
}
GET
/v1/content/items/{itemId}
Resolves an item to the content it belongs to, plus the item's title, part and duration, so a player link can be built.
{
"contentId": "cnt_9x8y7z",
"title": "Studio Time",
"partId": "part_1a2b3c",
"duration": 1864
}
GET
/v1/content/display/{domain}
Displayable content for a domain, paginated.
| Query | Type | Description |
|---|---|---|
| skip | integer required | Number of items to skip. |
| limit | integer required | Maximum items to return. |
curl "https://api.meuspace.com/v1/content/display/yourname?skip=0&limit=5" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
{
"content": [
{
"title": "Live from the studio",
"duration": 1864,
"artwork": "https://cdn.meuspace.com/art.jpg",
"type": "video",
"isLive": false,
"firstItemId": "item_1a2b3c",
"created": "2026-03-02T14:05:47",
"formats": ["mp4"],
"hashtags": ["studio"],
"artist": [ { "name": "Your Name", "avatar": "https://cdn.meuspace.com/avatar.jpg" } ],
"contributors": [
{ "publicId": "art_1a2b3c", "name": "Your Name", "role": "artist", "avatar": "https://cdn.meuspace.com/avatar.jpg", "nsubs": 1284, "publicKey": "2a305a9d..." }
],
"liveData": null,
"collectionData": null
}
]
}
GET
/v1/content/search/{domain}
Searches displayable content for a domain. Returns the same shape as /display.
| Query | Type | Description |
|---|---|---|
| skip | integer required | Number of items to skip. |
| limit | integer required | Maximum items to return. |
| regex | string required | Search expression. |
curl "https://api.meuspace.com/v1/content/search/yourname?skip=0&limit=12®ex=studio" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
Collections
Group content into releases, albums and playlists.
These endpoints are not live yet. Requests and responses below are illustrative dummy data so you can design against the shape early.
POST
/v1/collection
Create a new collection.
| Field | Type | Description |
|---|---|---|
| title | string required | Public title of the collection. |
| type | string required | One of Single, ExtendedPlay, Album, PlaylistRelease, BundleRelease, VideoRelease, MultimediaRelease. |
| artworkPath | string optional | Cover artwork URL. |
| templateId | string optional | Template used to create the collection's content. |
| releaseProprietaryIds | array optional | External identifiers as { namespace, value } pairs. |
| retentionType | string optional | STATIC or DINAMIC. |
curl -X POST https://api.meuspace.com/v1/collection \
-H "Authorization: Bearer $MEUSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Studio Sessions",
"type": "BundleRelease",
"artworkPath": "https://cdn.meuspace.com/art.jpg",
"templateId": "tpl_1a2b3c",
"retentionType": "DINAMIC"
}'
{
"publicId": "col_1a2b3c",
"title": "Studio Sessions",
"type": "BundleRelease",
"artworkPath": "https://cdn.meuspace.com/art.jpg",
"created": "2026-01-14T09:32:11",
"proprietaryIds": [
{ "namespace": "MEUSTREAMS:ReleaseReference", "value": "196589201234" }
]
}
GET
/v1/collection
List every collection on your space, newest first.
curl "https://api.meuspace.com/v1/collection" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
{
"collections": [
{
"publicId": "col_1a2b3c",
"title": "Studio Sessions",
"type": "BundleRelease",
"artworkPath": "https://cdn.meuspace.com/art.jpg",
"created": "2026-01-14T09:32:11"
}
]
}
GET
/v1/collection/{collectionId}
Retrieve a single collection and the content it contains.
curl "https://api.meuspace.com/v1/collection/col_1a2b3c" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
{
"collection": {
"publicId": "col_1a2b3c",
"title": "Studio Sessions",
"type": "BundleRelease",
"artworkPath": "https://cdn.meuspace.com/art.jpg",
"created": "2026-01-14T09:32:11"
},
"contents": [
{
"publicId": "cnt_9x8y7z",
"title": "Live from the studio",
"status": "RECORDED",
"duration": 1864,
"artwork": "https://cdn.meuspace.com/art.jpg",
"created": "2026-01-14T09:32:11"
}
],
"artistId": "art_1a2b3c"
}
PATCH
/v1/collection/{collectionId}
Update an existing collection. Send only the fields you want to change.
| Field | Type | Description |
|---|---|---|
| title | string optional | New public title. |
| artworkPath | string optional | New cover artwork URL. |
| retentionType | string optional | STATIC or DINAMIC. |
curl -X PATCH https://api.meuspace.com/v1/collection/col_1a2b3c \
-H "Authorization: Bearer $MEUSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "title": "Studio Sessions Vol. 2" }'
{
"publicId": "col_1a2b3c",
"title": "Studio Sessions Vol. 2",
"type": "BundleRelease",
"artworkPath": "https://cdn.meuspace.com/art.jpg",
"created": "2026-01-14T09:32:11"
}
Templates
Reusable blueprints for the content you publish.
These endpoints are not live yet. Requests and responses below are illustrative dummy data so you can design against the shape early.
POST
/v1/template
Create a new template. Templates define the defaults applied to content created from them.
| Field | Type | Description |
|---|---|---|
| title | string required | Template name. |
| description | string optional | Default description for content. |
| hashtags | array optional | Default hashtags. |
| license | string optional | FREE, PROMOTED or MEMBER. |
| contentItemType | string optional | One of the ContentItemType values, e.g. ShortFormNonMusicalWorkVideo. |
| retention | object optional | { time, unit, type }; unit is HOURS, DAYS, WEEKS, MONTHS or YEARS. |
| shouldRecord | boolean optional | Whether live items are recorded. |
| chatConfiguration | object optional | { showChat, visibility }; visibility is CLOSED, ANONYMOUS, OPEN, FOLLOWERS or MEMBERS. |
| donationsConfiguration | object optional | { isActive, note, thankYouMessages }. |
| parentalWarningType | string optional | Parental advisory label. |
| countries | array optional | ISO country codes the template is available in. |
| versioning | object optional | Versioning rules for items created from the template. |
curl -X POST https://api.meuspace.com/v1/template \
-H "Authorization: Bearer $MEUSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Live set",
"description": "Weekly live stream",
"hashtags": ["live", "studio"],
"license": "FREE",
"contentItemType": "ShortFormNonMusicalWorkVideo",
"shouldRecord": true,
"retention": { "time": 30, "unit": "DAYS", "type": "DINAMIC" },
"chatConfiguration": { "showChat": true, "visibility": "OPEN" },
"donationsConfiguration": { "isActive": true, "note": "Support the stream", "thankYouMessages": ["Thanks!"] },
"parentalWarningType": "None",
"countries": ["US", "BR"]
}'
{
"publicId": "tpl_1a2b3c",
"title": "Live set",
"description": "Weekly live stream",
"hashtags": ["live", "studio"],
"license": "FREE",
"contentItemType": "ShortFormNonMusicalWorkVideo",
"shouldRecord": true,
"parentalWarningType": "None",
"countries": ["US", "BR"],
"created": "2026-01-14T09:32:11"
}
GET
/v1/template
List every template on your space, newest first.
curl "https://api.meuspace.com/v1/template" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
{
"templates": [
{
"publicId": "tpl_1a2b3c",
"title": "Live set",
"hashtags": ["live", "studio"],
"license": "FREE",
"contentItemType": "ShortFormNonMusicalWorkVideo",
"shouldRecord": true,
"created": "2026-01-14T09:32:11"
}
]
}
GET
/v1/template/{templateId}
Retrieve a single template and all of its defaults.
curl "https://api.meuspace.com/v1/template/tpl_1a2b3c" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
{
"publicId": "tpl_1a2b3c",
"title": "Live set",
"description": "Weekly live stream",
"hashtags": ["live", "studio"],
"license": "FREE",
"contentItemType": "ShortFormNonMusicalWorkVideo",
"retention": { "time": 30, "unit": "DAYS", "type": "DINAMIC" },
"shouldRecord": true,
"chatConfiguration": { "showChat": true, "visibility": "OPEN" },
"donationsConfiguration": { "isActive": true, "note": "Support the stream", "thankYouMessages": ["Thanks!"] },
"parentalWarningType": "None",
"countries": ["US", "BR"],
"created": "2026-01-14T09:32:11"
}
PATCH
/v1/template/{templateId}
Update an existing template. Send only the fields you want to change; the same fields as create are accepted.
curl -X PATCH https://api.meuspace.com/v1/template/tpl_1a2b3c \
-H "Authorization: Bearer $MEUSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "title": "Live set (encore)", "shouldRecord": false }'
{
"publicId": "tpl_1a2b3c",
"title": "Live set (encore)",
"description": "Weekly live stream",
"hashtags": ["live", "studio"],
"license": "FREE",
"contentItemType": "ShortFormNonMusicalWorkVideo",
"shouldRecord": false,
"parentalWarningType": "None",
"countries": ["US", "BR"],
"created": "2026-01-14T09:32:11"
}
Audience
Reach your people directly, with no algorithm in between.
GET
/v1/audience/subscribers
List the people subscribed to your space.
{
"data": [
{ "id": "sub_2k9d1", "display_name": "Alex R.", "status": "active", "tier": "supporter", "since": "2025-11-02T18:20:00Z" },
{ "id": "sub_7m3p8", "display_name": "Jamie T.", "status": "active", "tier": "free", "since": "2026-01-19T11:02:35Z" }
],
"has_more": true,
"next_cursor": "c3VianNjcmlwdGlvbg"
}
GET
/v1/audience/subscribers/{id}
Retrieve a single subscriber, including their tier and engagement summary.
{
"id": "sub_2k9d1",
"display_name": "Alex R.",
"status": "active",
"tier": "supporter",
"messages_sent": 42,
"lifetime_value_cents": 8600,
"since": "2025-11-02T18:20:00Z"
}
POST
/v1/audience/messages
Send a message to some or all of your audience. Delivery is direct and chronological.
| Field | Type | Description |
|---|---|---|
| channel | string required | feed, email, or push. |
| subject | string required | Short subject line. |
| body | string required | Message body, plain text or Markdown. |
| audience | string optional | all, supporter, or a subscriber ID. Defaults to all. |
curl -X POST https://api.meuspace.com/v1/audience/messages \
-H "Authorization: Bearer $MEUSPACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel": "feed",
"subject": "New set is live",
"body": "Thanks for the support, the new episode is up now.",
"audience": "all"
}'
GET
/v1/audience/stats
A snapshot of subscriber growth, engagement and earnings.
{
"subscribers": { "total": 1284, "active": 1176, "new_this_month": 93 },
"engagement": { "feed_open_rate": 0.62, "avg_watch_minutes": 18.4 },
"revenue": { "currency": "USD", "gross_cents": 482150, "your_earnings_cents": 482150 }
}
Nostr
Your data lives on relays, not in a silo.
Overview
Meuspace is built on Nostr. Every time you publish, your content is signed with your keypair and sent out as a Nostr event to a set of relays — independent servers that store and forward events. Nothing is trapped in a single database, so anyone can pull your events back out of the relay network.
1. You publish
You create content in Meuspace and it is signed with your own key.
2. Relays receive it
The signed event is broadcast to every relay your space publishes to.
3. Anyone can pull it
Any client, yours or a third party's, can fetch your events from any relay.
Portable by design. If you ever move on, your events are already on the relay network — re-fetchable by any Nostr client, with no export step and no lock-in.
GET
/v1/nostr/relays
List the relays your space publishes to, and the read/write permissions for each.
{
"data": [
{ "url": "wss://relay.meuspace.com", "read": true, "write": true, "status": "connected" },
{ "url": "wss://relay.damus.io", "read": true, "write": true, "status": "connected" },
{ "url": "wss://nos.lol", "read": true, "write": false, "status": "connected" }
]
}
GET
/v1/nostr/events
Pull your content back as raw Nostr events. This is a thin convenience layer over the relay network — by default it returns events authored by your own key.
| Query | Type | Description |
|---|---|---|
| kinds | string optional | Comma-separated event kinds, e.g. 1,30023. |
| authors | string optional | Filter by pubkey. Defaults to your own. |
| since | integer optional | Unix timestamp — only events at or after this time. |
| until | integer optional | Unix timestamp — only events at or before this time. |
| limit | integer optional | Maximum events to return, 1–500. Defaults to 100. |
| cursor | string optional | Opaque cursor from a previous response. |
curl "https://api.meuspace.com/v1/nostr/events?kinds=30023,1&limit=2" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
{
"data": [
{
"id": "a3f1c8d2e4b7a091fe63aa1c5b8d2f70c4e9b1a6d3f8c2e5b7a0d9f1c3e5b7a0",
"pubkey": "npub1yourname8f3k2m0q9w7e4r2t6y",
"created_at": 1772540400,
"kind": 30023,
"tags": [["d", "live-from-the-studio"], ["title", "Live from the studio"]],
"content": "Thanks for the support, the new set is up now.",
"sig": "b7c1e42d9f0a3c5e8b2d4f6a1c3e5b7d9f0a2c4e6b8d1f3a5c7e9b2d4f6a8c"
}
],
"has_more": false,
"next_cursor": null
}
Event shape
Every item above is a standard NIP-01 event. The id is a hash of the serialized event and sig verifies against pubkey, so anyone can independently verify that a piece of content is really yours.
{
"id": "a3f1c8d2e4b7a091fe63aa1c5b8d2f70c4e9b1a6d3f8c2e5b7a0d9f1c3e5b7a0",
"pubkey": "npub1yourname8f3k2m0q9w7e4r2t6y",
"created_at": 1772540400,
"kind": 30023,
"tags": [
["d", "live-from-the-studio"],
["title", "Live from the studio"],
["t", "meuspace"]
],
"content": "Thanks for the support, the new set is up now.",
"sig": "b7c1e42d9f0a3c5e8b2d4f6a1c3e5b7d9f0a2c4e6b8d1f3a5c7e9b2d4f6a8c"
}
| Kind | Content |
|---|---|
| 0 | Profile metadata (your public identity). |
| 1 | Short text note — feed posts and updates. |
| 1063 | File metadata — media you publish. |
| 30023 | Long-form content (articles and long posts). |
| 30078 | App-specific data, such as Meuspace settings. |
Because relays are interchangeable, the same event can be fetched from any of them. A relay going down never takes your content with it.
Reference
Status codes, limits and lists.
Errors
Errors use conventional HTTP status codes and return a JSON body with a machine-readable code.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The request body or parameters are malformed. |
| 401 | unauthorized | Missing, expired or invalid bearer token. |
| 403 | forbidden | The token is valid but not allowed to reach this resource (e.g. a missing or unlisted origin on browser-facing routes). |
| 404 | not_found | The requested resource does not exist. |
| 409 | conflict | The resource is in a conflicting state. |
| 422 | unprocessable | Validation failed for one or more fields. |
| 429 | rate_limited | Too many requests. Back off and retry. |
| 500 | server_error | Something went wrong on our side. |
{
"error": {
"code": "unprocessable",
"message": "The field 'title' is required.",
"field": "title"
}
}
Rate limits
Limits apply per API key. Responses include headers so you can adapt before you are throttled.
| Scope | Limit |
|---|---|
| Read endpoints | 120 requests / minute |
| Write endpoints | 60 requests / minute |
| Broadcasts | 30 requests / hour |
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1772540400
Pagination
Paginated endpoints use skip and limit query parameters. Pass the number of items to skip and the maximum to return, then increase skip by limit to walk through the pages.
curl "https://api.meuspace.com/v1/content/display/yourname?skip=0&limit=20" \
-H "Authorization: Bearer $MEUSPACE_API_KEY"
skip and limit are plain integers. Keep limit modest so responses stay fast and within the rate limits.
Ready to build on your own space?
Request an API key for your space and start shipping on your own domain.
Get Your Space