📚 Developer Documentation

Complete guide to integrating SnapieAudioPlayer

🚀 Getting Started

SnapieAudioPlayer provides a REST API for uploading, storing, and playing audio files on the decentralized IPFS network. All audio files are stored permanently on IPFS and metadata is indexed in our MongoDB database for fast retrieval.

✓ Base URL: https://audio.3speak.tv

Quick Start

  1. Get an API key (contact 3speak team)
  2. Upload audio via REST API
  3. Embed player using returned permlink or CID
  4. Track plays and engagement

🔐 Authentication

API keys are required for uploading audio. Include your API key in the request header:

X-API-Key: sk_your_api_key_here
Note: Reading audio metadata and playback do not require authentication. Only uploads are protected.

📺 Embedding Player

Using iFrame

<!-- Embed by permlink -->
<iframe 
  src="https://audio.3speak.tv/play?a=abc123xyz"
  width="100%" 
  height="120"
  frameborder="0"
  allow="autoplay">
</iframe>

<!-- Embed by IPFS CID -->
<iframe 
  src="https://audio.3speak.tv/play?cid=QmdMsEXyDe5Z4S3n8THfYgFP1iH3ngCeCytdHnndzqdZAK"
  width="100%" 
  height="120"
  frameborder="0">
</iframe>

Display Modes

Mode Height Description
minimal 80px Play button, waveform, time only
compact 120px Default - full controls without metadata
full 180px All controls + title, owner, plays
<iframe src="https://audio.3speak.tv/play?a=abc123&mode=minimal" height="80"></iframe>

Iframe Mode (No Scrollbars)

Add &iframe=1 for clean embedding without scrollbars - perfect for chat apps:

<!-- Clean embed with no scrollbars -->
<iframe 
  src="https://audio.3speak.tv/play?a=abc123&mode=compact&iframe=1"
  width="100%" 
  height="120"
  frameborder="0"
  scrolling="no"
  allow="autoplay">
</iframe>
💡 Tip: Use iframe=1 to remove all padding and prevent scrollbars. Ideal for seamless integration in chat apps or tight spaces.

📤 Upload API

POST /api/audio/upload

Upload audio files to IPFS with metadata indexing.

Headers

Header Required Description
X-API-Key Yes Your API key
X-User Yes Username (required for all uploads)
Content-Type Yes multipart/form-data

Form Data Parameters

Parameter Type Required Description
audio File Yes Audio file (mp3, m4a, ogg, webm, wav)
duration Number Yes Duration in seconds
format String Yes File format (mp3, m4a, etc.)
title String No Audio title
description String No Audio description
tags JSON Array No Array of tag strings for content discovery (e.g., ["music", "podcast"])
codec String No Audio codec (aac, mp3, etc.)
bitrate Number No Bitrate in kbps
sampleRate Number No Sample rate in Hz
channels Number No Number of channels (1=mono, 2=stereo)
waveform JSON No Waveform data object
thumbnail_url String (URL) No Cover art/thumbnail URL (max 2048 chars, http/https only)
category String No Content type: voice_message (default), podcast, song, interview, audiobook, noise_sample
post_permlink String No Blockchain post reference (e.g., Hive permlink) for linking comments/reactions (max 256 chars)
⚠️ File Limits & Requirements:
  • Max file size: 50MB
  • Supported formats: mp3, m4a, ogg, webm, wav
  • Rate limit: 10 uploads per minute
  • Username required: X-User header must be provided
  • Banned users: Users with upload restrictions will receive 403 Forbidden

Response

{
  "success": true,
  "permlink": "w2ehm8pr",
  "cid": "QmdMsEXyDe5Z4S3n8THfYgFP1iH3ngCeCytdHnndzqdZAK",
  "playUrl": "https://audio.3speak.tv/play?a=w2ehm8pr",
  "apiUrl": "https://audio.3speak.tv/api/audio?a=w2ehm8pr"
}

▶️ Playback API

GET /api/audio

Retrieve audio metadata for playback. No authentication required.

Query Parameters

Parameter Description Example
a Audio permlink ?a=w2ehm8pr
cid IPFS Content ID ?cid=QmdMsEX...

Response

{
  "permlink": "w2ehm8pr",
  "owner": "meno",
  "audio_cid": "QmdMsEXyDe5Z4S3n8THfYgFP1iH3ngCeCytdHnndzqdZAK",
  "category": "voice_message",
  "duration": 45,
  "format": "mp3",
  "bitrate": 128,
  "sampleRate": 44100,
  "channels": 1,
  "waveform": {
    "peaks": [0.05, 0.34, 0.93, ...],
    "samples": 100
  },
  "audioUrl": "http://gateway.ipfs/ipfs/QmdMsEX...",
  "audioUrlFallback": "https://ipfs.io/ipfs/QmdMsEX...",
  "title": "My Audio",
  "description": "This is an example audio recording",
  "tags": ["music", "podcast", "interview"],
  "thumbnail_url": "https://files.hive.blog/file/hiveimages/abc123.jpg",
  "post_permlink": "my-audio-snap-2026",
  "plays": 42,
  "likes": 5,
  "createdAt": "2025-11-27T01:22:17.053Z"
}

Get Audio Feed

GET /api/audio/feed

Get a paginated feed of audio content with filtering and sorting options. Perfect for building frontends with discovery feeds, trending pages, tag browsing, and user profiles. No authentication required.

Query Parameters

Parameter Type Default Description
limit Number 20 Items per page (max 100)
offset Number 0 Pagination offset
sort String newest Sort order: newest, oldest, plays, trending
category String - Filter by category: voice_message, podcast, song, interview, audiobook, noise_sample
tag String - Filter by tag (e.g., "music", "podcast")
owner String - Filter by username (user's audio only)

Example Requests

# Latest audio (newest first)
GET /api/audio/feed?limit=20&offset=0&sort=newest

# Trending audio (most played)
GET /api/audio/feed?sort=plays

# All podcasts, sorted by newest
GET /api/audio/feed?category=podcast&sort=newest

# Audio tagged with "music"
GET /api/audio/feed?tag=music&limit=50

# User's audio profile
GET /api/audio/feed?owner=meno&sort=newest

# Paginated results (page 2)
GET /api/audio/feed?limit=20&offset=20

Response

{
  "items": [
    {
      "permlink": "abc123xy",
      "owner": "meno",
      "audio_cid": "QmdMsEX...",
      "category": "podcast",
      "duration": 1800,
      "format": "mp3",
      "title": "My Podcast Episode",
      "description": "Episode description here",
      "tags": ["podcast", "tech", "interview"],
      "thumbnail_url": "https://files.hive.blog/.../cover.jpg",
      "post_permlink": "my-podcast-ep1",
      "plays": 152,
      "likes": 23,
      "createdAt": "2026-02-20T10:30:00Z",
      "audioUrl": "https://ipfs.3speak.tv/ipfs/QmdMsEX...",
      "audioUrlFallback": "https://ipfs.io/ipfs/QmdMsEX..."
    },
    // ... more items
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 156,
    "hasMore": true
  },
  "filters": {
    "sort": "newest",
    "category": null,
    "tag": null,
    "owner": null
  }
}
💡 Use Cases:
  • Home Feed: ?sort=newest&limit=20
  • Trending Page: ?sort=plays&limit=50
  • Tag Browser: ?tag=music&sort=plays
  • User Profile: ?owner=username&sort=newest
  • Category Page: ?category=podcast&sort=newest

Update Thumbnail

PATCH /api/audio/:permlink/thumbnail

Update the thumbnail URL for an existing audio. Authentication required. Only the audio owner can update their thumbnails.

Request Body

PATCH /api/audio/w2ehm8pr/thumbnail
Content-Type: application/json
X-API-Key: sk_your_api_key
X-User: meno

{
  "thumbnail_url": "https://files.hive.blog/file/hiveimages/new-image.jpg"
}

Response

{
  "success": true,
  "permlink": "w2ehm8pr",
  "thumbnail_url": "https://files.hive.blog/file/hiveimages/new-image.jpg"
}
Validation Rules:
  • URL must be valid (http:// or https://)
  • Maximum length: 2048 characters
  • Only owner can update (validated via X-User header)

Update Blockchain Post Permlink

PATCH /api/audio/:permlink/post-permlink

Update the blockchain post permlink for an existing audio. Authentication required. Only the audio owner can update their post permlink.

Request Body

PATCH /api/audio/w2ehm8pr/post-permlink
Content-Type: application/json
X-API-Key: sk_your_api_key
X-User: meno

{
  "post_permlink": "my-audio-snap-2026"
}

Response

{
  "success": true,
  "permlink": "w2ehm8pr",
  "post_permlink": "my-audio-snap-2026"
}
Validation Rules:
  • Must be alphanumeric with hyphens/underscores only
  • Maximum length: 256 characters
  • Only owner can update (validated via X-User header)

Track Play Count

POST /api/audio/play

Increment play counter when audio starts playing.

POST /api/audio/play
Content-Type: application/json

{
  "permlink": "w2ehm8pr"
}

Response:
{
  "success": true,
  "plays": 43
}

💻 Code Examples

JavaScript (Fetch API)

// Upload audio file
async function uploadAudio(file) {
  const formData = new FormData();
  formData.append('audio', file);
  formData.append('duration', 45);
  formData.append('format', 'mp3');
  formData.append('title', 'My Recording');
  formData.append('thumbnail_url', 'https://files.hive.blog/file/hiveimages/cover.jpg');
  formData.append('category', 'podcast');
  formData.append('post_permlink', 'my-audio-snap-2026');
  formData.append('tags', JSON.stringify(['music', 'podcast']));

  const response = await fetch('https://audio.3speak.tv/api/audio/upload', {
    method: 'POST',
    headers: {
      'X-API-Key': 'sk_your_api_key',
      'X-User': 'username'
    },
    body: formData
  });

  return await response.json();
}

// Get audio metadata
async function getAudio(permlink) {
  const response = await fetch(
    `https://audio.3speak.tv/api/audio?a=${permlink}`
  );
  return await response.json();
}

// Get audio feed
async function getFeed(options = {}) {
  const {
    limit = 20,
    offset = 0,
    sort = 'newest',
    category,
    tag,
    owner
  } = options;

  const params = new URLSearchParams({
    limit,
    offset,
    sort
  });

  if (category) params.append('category', category);
  if (tag) params.append('tag', tag);
  if (owner) params.append('owner', owner);

  const response = await fetch(
    `https://audio.3speak.tv/api/audio/feed?${params}`
  );
  return await response.json();
}

// Example: Get trending podcasts
async function getTrendingPodcasts() {
  return await getFeed({
    category: 'podcast',
    sort: 'plays',
    limit: 50
  });
}

// Example: Get user's audio
async function getUserAudio(username) {
  return await getFeed({
    owner: username,
    sort: 'newest'
  });
}

// Track play
async function trackPlay(permlink) {
  await fetch('https://audio.3speak.tv/api/audio/play', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ permlink })
  });
}

// Update thumbnail
async function updateThumbnail(permlink, thumbnailUrl) {
  const response = await fetch(
    `https://audio.3speak.tv/api/audio/${permlink}/thumbnail`,
    {
      method: 'PATCH',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': 'sk_your_api_key',
        'X-User': 'username'
      },
      body: JSON.stringify({ thumbnail_url: thumbnailUrl })
    }
  );
  return await response.json();
}

// Update Post Permlink
async function updatePostPermlink(permlink, postPermlink) {
  const response = await fetch(
    `https://audio.3speak.tv/api/audio/${permlink}/post-permlink`,
    {
      method: 'PATCH',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': 'sk_your_api_key',
        'X-User': 'username'
      },
      body: JSON.stringify({ post_permlink: postPermlink })
    }
  );
  return await response.json();
}

cURL

# Upload audio
curl -X POST https://audio.3speak.tv/api/audio/upload \
  -H "X-API-Key: sk_your_api_key" \
  -H "X-User: username" \
  -F "audio=@recording.mp3" \
  -F "duration=45" \
  -F "format=mp3" \
  -F "title=My Recording" \
  -F "thumbnail_url=https://files.hive.blog/file/hiveimages/cover.jpg" \
  -F "category=podcast" \
  -F "post_permlink=my-audio-snap-2026" \
  -F "tags=[\"music\",\"podcast\"]"

# Get metadata
curl "https://audio.3speak.tv/api/audio?a=w2ehm8pr"

# Get feed (latest audio)
curl "https://audio.3speak.tv/api/audio/feed?limit=20&offset=0&sort=newest"

# Get trending podcasts
curl "https://audio.3speak.tv/api/audio/feed?category=podcast&sort=plays&limit=50"

# Get audio tagged with 'music'
curl "https://audio.3speak.tv/api/audio/feed?tag=music"

# Get user's audio
curl "https://audio.3speak.tv/api/audio/feed?owner=meno&sort=newest"

# Track play
curl -X POST https://audio.3speak.tv/api/audio/play \
  -H "Content-Type: application/json" \
  -d '{"permlink":"w2ehm8pr"}'

# Update thumbnail
curl -X PATCH https://audio.3speak.tv/api/audio/w2ehm8pr/thumbnail \
  -H "X-API-Key: sk_your_api_key" \
  -H "X-User: username" \
  -H "Content-Type: application/json" \
  -d '{"thumbnail_url":"https://files.hive.blog/file/hiveimages/new.jpg"}'

# Update post permlink
curl -X PATCH https://audio.3speak.tv/api/audio/w2ehm8pr/post-permlink \
  -H "X-API-Key: sk_your_api_key" \
  -H "X-User: username" \
  -H "Content-Type: application/json" \
  -d '{"post_permlink":"my-audio-snap-2026"}'

Python

import requests

# Upload audio
def upload_audio(file_path, api_key):
    with open(file_path, 'rb') as f:
        files = {'audio': f}
        data = {
            'duration': 45,
            'format': 'mp3',
            'title': 'My Recording',
            'thumbnail_url': 'https://files.hive.blog/file/hiveimages/cover.jpg',
            'category': 'podcast',
            'post_permlink': 'my-audio-snap-2026',
            'tags': '["music", "podcast"]'
        }
        headers = {
            'X-API-Key': api_key,
            'X-User': 'username'
        }
        
        response = requests.post(
            'https://audio.3speak.tv/api/audio/upload',
            files=files,
            data=data,
            headers=headers
        )
        return response.json()

# Get metadata
def get_audio(permlink):
    response = requests.get(
        f'https://audio.3speak.tv/api/audio?a={permlink}'
    )
    return response.json()

# Get feed with filters
def get_feed(limit=20, offset=0, sort='newest', category=None, tag=None, owner=None):
    params = {
        'limit': limit,
        'offset': offset,
        'sort': sort
    }
    
    if category:
        params['category'] = category
    if tag:
        params['tag'] = tag
    if owner:
        params['owner'] = owner
    
    response = requests.get(
        'https://audio.3speak.tv/api/audio/feed',
        params=params
    )
    return response.json()

# Example: Get trending podcasts
def get_trending_podcasts():
    return get_feed(category='podcast', sort='plays', limit=50)

# Example: Get user's audio
def get_user_audio(username):
    return get_feed(owner=username, sort='newest')

⏱️ Rate Limits

Endpoint Limit Window
Upload /api/audio/upload 10 requests 1 minute
Play tracking /api/audio/play 100 requests 1 minute
Metadata /api/audio Unlimited -
Feed /api/audio/feed Unlimited -
Rate Limit Headers:
  • X-RateLimit-Limit - Max requests allowed
  • X-RateLimit-Remaining - Remaining requests
  • X-RateLimit-Reset - Time when limit resets (Unix timestamp)

❌ Error Handling

HTTP Status Codes

Code Meaning Description
200 OK Request successful
201 Created Upload successful
400 Bad Request Invalid parameters or file format
401 Unauthorized Missing or invalid API key
403 Forbidden User is banned or lacks upload permissions
404 Not Found Audio not found
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error

Error Response Format

{
  "error": "Invalid file format",
  "message": "Allowed formats: mp3, m4a, ogg, webm, wav"
}

Common Errors

Invalid API Key
{
  "error": "Invalid API key",
  "message": "The provided API key is not valid"
}
File Too Large
{
  "error": "File too large",
  "message": "Maximum file size is 50MB"
}
Rate Limit Exceeded
{
  "error": "Too many requests, please try again later"
}
User Banned
{
  "error": "Upload not allowed",
  "message": "User is banned from uploading"
}
Missing Username
{
  "error": "Username required",
  "message": "X-User header must be provided for uploads"
}
← Back to Home