agentsclimarketplace

Verify account

Skill meetstream-ai/claude-plugin/skills/verify-account

Verify a MeetStream account's configuration before building. Checks API key validity, which transcription providers are configured (deepgram / assemblyai / sarvam / jigsawstack / meetstream), webhook URL reachability, and surfaces any missing provider keys. Use when the user says "verify my MeetStream account", "check setup", "which providers do I have", "test API key", "diagnose meetstream", or before any other build skill runs.From its SKILL.md

Install
npx -y skills add meetstream-ai/claude-plugin --skill verify-account

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

8.2 KB, as published. Nobody here has run it

Verify MeetStream Account

Run a comprehensive health check on the user's MeetStream account before scaffolding anything. Catches the most common cause of build failures: missing or misconfigured provider keys.

Step 0: Make sure there's an API key to verify

If MEETSTREAM_API_KEY is unset, invoke the getting-started skill first — without an account + key, there's nothing to verify. Signup is at https://app.meetstream.ai.

What to do

  1. Get the API key. Ask the user, or read it from MEETSTREAM_API_KEY env var. Never log it.

  2. Run the verification script. Write it to a temp file and execute. Capture the report.

  3. Present the report. Clearly mark each provider as ✅ configured / ❌ not configured / ⚠️ unknown.

  4. Recommend next steps based on what works.

The verification script

Write this to /tmp/meetstream_verify.py and run it:

#!/usr/bin/env python3
"""MeetStream account verifier. Reports which providers/features are configured."""
import json, os, sys, urllib.request, urllib.error

KEY = os.environ.get("MEETSTREAM_API_KEY") or (sys.argv[1] if len(sys.argv) > 1 else "")
if not KEY:
    print("❌ No API key. Set MEETSTREAM_API_KEY or pass as arg.")
    sys.exit(2)

BASE = "https://api.meetstream.ai/api/v1"
HEADERS = {"Authorization": f"Token {KEY}", "Content-Type": "application/json"}

def req(method, path, body=None):
    url = f"{BASE}{path}"
    data = json.dumps(body).encode() if body else None
    r = urllib.request.Request(url, headers=HEADERS, data=data, method=method)
    try:
        resp = urllib.request.urlopen(r)
        return resp.status, json.loads(resp.read())
    except urllib.error.HTTPError as e:
        try: body = json.loads(e.read())
        except: body = {}
        return e.code, body
    except Exception as e:
        return 0, {"error": str(e)}

print("=" * 60)
print("MeetStream account verification")
print("=" * 60)

# 1. API key validity
print("\n[1] API key validity")
code, body = req("GET", "/bots")
if code == 200:
    print(f"   ✅ API key valid. {len(body.get('bots',[]))} bots visible on first page.")
elif code in (401, 403):
    print(f"   ❌ API key rejected (HTTP {code}). Get a fresh key at https://app.meetstream.ai/api-keys")
    sys.exit(1)
else:
    print(f"   ⚠ Unexpected: HTTP {code}: {body}")

# 2. Probe each post-call provider by creating a tiny test bot and reading the error message
print("\n[2] Post-call transcription providers")
providers = {
    "deepgram":   {"deepgram": {"model": "nova-3", "language": "en"}},
    "assemblyai": {"assemblyai": {"speech_models": ["universal-2"], "language_code": "en_us",
                                    "speaker_labels": True, "punctuate": True, "format_text": True,
                                    "filter_profanity": False, "redact_pii": False,
                                    "auto_chapters": False, "entity_detection": False}},
    "sarvam":     {"sarvam": {"model": "saaras:v3", "language_code": "en-IN", "mode": "transcribe", "with_diarization": True}},
    "jigsawstack": {"jigsawstack": {"language": "auto", "translate": False, "by_speaker": True}},
    "meetstream": {"meetstream": {"language": "en", "translate": False}},
}

probe_bots = []
for name, provider in providers.items():
    payload = {
        "meeting_link": f"https://meet.google.com/verify-probe-{name}",
        "bot_name": f"verify-{name}",
        "video_required": False,
        "recording_config": {
            "transcript": {"provider": provider},
            "retention": {"type": "timed", "hours": 1},
        },
        "automatic_leave": {
            "waiting_room_timeout": 600, "everyone_left_timeout": 600,
            "voice_inactivity_timeout": 600, "in_call_recording_timeout": 600,
            "recording_permission_denied_timeout": 300,
        },
    }
    code, body = req("POST", "/bots/create_bot", payload)
    if code == 201:
        # Provider config accepted by API. transcript_id presence indicates the provider is set up.
        tid = body.get("transcript_id")
        probe_bots.append(body.get("bot_id"))
        if tid:
            print(f"   ✅ {name:12} configured (transcript_id reserved)")
        else:
            print(f"   ⚠ {name:12} accepted but no transcript_id returned")
    elif code == 400:
        # 400 often indicates config validation issue (could be missing key)
        msg = body.get("message", str(body))[:100]
        print(f"   ❌ {name:12} rejected: {msg}")
    else:
        print(f"   ⚠ {name:12} HTTP {code}: {body}")

# 3. Probe streaming providers (similar — but with live webhook URL)
print("\n[3] Streaming providers")
streaming = {
    "meetstream_streaming": {"meetstream_streaming": {}},
    "meeting_captions":     {"meeting_captions": {}},
}
for name, provider in streaming.items():
    payload = {
        "meeting_link": f"https://meet.google.com/verify-probe-{name}",
        "bot_name": f"verify-{name}",
        "video_required": False,
        "live_transcription_required": {"webhook_url": "https://example.com/probe"},
        "recording_config": {
            "transcript": {"provider": provider},
            "retention": {"type": "timed", "hours": 1},
        },
        "automatic_leave": {
            "waiting_room_timeout": 600, "everyone_left_timeout": 600,
            "voice_inactivity_timeout": 600, "in_call_recording_timeout": 600,
            "recording_permission_denied_timeout": 300,
        },
    }
    code, body = req("POST", "/bots/create_bot", payload)
    if code == 201:
        probe_bots.append(body.get("bot_id"))
        print(f"   ✅ {name:24} configured")
    else:
        msg = body.get("message", str(body))[:100]
        print(f"   ❌ {name:24} HTTP {code}: {msg}")

# 4. Endpoint reachability
print("\n[4] Core endpoints")
for label, method, path in [
    ("GET /bots",               "GET",  "/bots"),
    ("GET /calendar",           "GET",  "/calendar"),
    ("GET /mia (list agents)",  "GET",  "/mia"),
]:
    code, _ = req(method, path)
    status = "✅" if 200 <= code < 300 else f"⚠ {code}"
    print(f"   {status:6} {label}")

# 5. Cleanup probe bots
print("\n[5] Cleanup probe bots")
for bid in probe_bots:
    code, _ = req("DELETE", f"/bots/{bid}/delete")
    print(f"   {'✅' if code == 200 else '⚠ ' + str(code)} deleted {bid}")

print("\n" + "=" * 60)
print("Done. See summary above.")
print("=" * 60)

How to read the report

  • ✅ on a provider = it's configured in your account, post-call/streaming bots with that provider will work
  • ❌ on a provider = key missing or invalid in MeetStream dashboard. Either add the key at https://app.meetstream.ai → Integrations, or use a different provider
  • meetstream_streaming and meeting_captions should always be ✅ — they don't need external keys

After the report

Recommend a build strategy based on what's configured:

  • All ✅ → user can pick any provider freely. Recommend deepgram (post-call accuracy) or meetstream_streaming (live, free)
  • Only meetstream_streaming works → recommend the live-streaming pattern + /transcribe fallback with whatever they DO have for post-call
  • No post-call providers, only meetstream_streaming → guide them to add at least one provider key in the dashboard before building the notetaker; otherwise /transcribe will fail too

Safety note

This skill does create real bots (1 per provider) against fake meeting links and immediately deletes them. The bots never join any actual meeting. Cleanup is automatic via DELETE /bots/{id}/delete. The script will print each deletion so the user can audit.

The destructive /delete is intentional and explicit in this verification context — the bots created here have no value. Outside this skill, do NOT auto-call /delete.

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.