Meuspace Logo
MEUSPACE
Home Docs API Reference

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.

REST v1
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
EnvironmentBase URLNotes
Productionhttps://api.meuspace.com/v1Live data, real payouts.
Sandboxhttps://api.sandbox.meuspace.com/v1Dummy 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.

FieldTypeDescription
handlestring optionalYour public handle, used in your default URL.
primary_domainstring optionalHostname to serve as the canonical domain.
timezonestring optionalIANA 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.

QueryTypeDescription
skipinteger requiredNumber of items to skip.
limitinteger requiredMaximum 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
    }
  ]
}

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.

FieldTypeDescription
titlestring requiredPublic title of the collection.
typestring requiredOne of Single, ExtendedPlay, Album, PlaylistRelease, BundleRelease, VideoRelease, MultimediaRelease.
artworkPathstring optionalCover artwork URL.
templateIdstring optionalTemplate used to create the collection's content.
releaseProprietaryIdsarray optionalExternal identifiers as { namespace, value } pairs.
retentionTypestring optionalSTATIC 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.

FieldTypeDescription
titlestring optionalNew public title.
artworkPathstring optionalNew cover artwork URL.
retentionTypestring optionalSTATIC 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.

FieldTypeDescription
titlestring requiredTemplate name.
descriptionstring optionalDefault description for content.
hashtagsarray optionalDefault hashtags.
licensestring optionalFREE, PROMOTED or MEMBER.
contentItemTypestring optionalOne of the ContentItemType values, e.g. ShortFormNonMusicalWorkVideo.
retentionobject optional{ time, unit, type }; unit is HOURS, DAYS, WEEKS, MONTHS or YEARS.
shouldRecordboolean optionalWhether live items are recorded.
chatConfigurationobject optional{ showChat, visibility }; visibility is CLOSED, ANONYMOUS, OPEN, FOLLOWERS or MEMBERS.
donationsConfigurationobject optional{ isActive, note, thankYouMessages }.
parentalWarningTypestring optionalParental advisory label.
countriesarray optionalISO country codes the template is available in.
versioningobject optionalVersioning 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.

FieldTypeDescription
channelstring requiredfeed, email, or push.
subjectstring requiredShort subject line.
bodystring requiredMessage body, plain text or Markdown.
audiencestring optionalall, 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.

QueryTypeDescription
kindsstring optionalComma-separated event kinds, e.g. 1,30023.
authorsstring optionalFilter by pubkey. Defaults to your own.
sinceinteger optionalUnix timestamp — only events at or after this time.
untilinteger optionalUnix timestamp — only events at or before this time.
limitinteger optionalMaximum events to return, 1–500. Defaults to 100.
cursorstring optionalOpaque 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"
}
KindContent
0Profile metadata (your public identity).
1Short text note — feed posts and updates.
1063File metadata — media you publish.
30023Long-form content (articles and long posts).
30078App-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.

StatusCodeMeaning
400invalid_requestThe request body or parameters are malformed.
401unauthorizedMissing, expired or invalid bearer token.
403forbiddenThe token is valid but not allowed to reach this resource (e.g. a missing or unlisted origin on browser-facing routes).
404not_foundThe requested resource does not exist.
409conflictThe resource is in a conflicting state.
422unprocessableValidation failed for one or more fields.
429rate_limitedToo many requests. Back off and retry.
500server_errorSomething 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.

ScopeLimit
Read endpoints120 requests / minute
Write endpoints60 requests / minute
Broadcasts30 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