✦ Developer API · v1.0

MeetGrade API

A clean REST API to pull your scored calls, QA results and checklists into any system — and receive a webhook the moment a call is graded.

REST · JSON Bearer auth 120 req/min Read-only (v1.0)

Introduction

The MeetGrade API is a REST API that speaks JSON over HTTPS. All requests go to the base URL below. Every response is UTF-8 JSON; timestamps are ISO 8601.

BASE URL https://app.meetgrade.com/api/v1

Version 1.0 is read-only — it lets you export data and react to events. Write endpoints are not part of this version.

Authentication

Authenticate every request with a Bearer token in the Authorization header. Create keys in the app under Settings → API keys.

Authorization: Bearer mg_live_xxxxxxxxxxxxxxxxxxxxxxxx
🔑 Shown once

A key's secret is revealed only once, at creation. Copy it immediately — we store only a hash and can't show it again.

⛔ Keep keys server-side

Never expose a key in browser code, mobile apps or public repos. Treat it like a password; revoke and rotate if leaked.

Rate limits

Each API key is limited to 120 requests per minute. Exceeding it returns HTTP 429 — back off and retry after a short pause.

GET /api/v1/calls

List your calls, newest first. Use limit and offset to paginate.

Query paramTypeDescription
limitintegerMax items, ≤ 200. Default 50.
offsetintegerItems to skip. Default 0.
cURL
curl https://app.meetgrade.com/api/v1/calls?limit=50 \
  -H "Authorization: Bearer mg_live_xxx"
Python
import requests

r = requests.get(
    "https://app.meetgrade.com/api/v1/calls",
    headers={"Authorization": "Bearer mg_live_xxx"},
    params={"limit": 50, "offset": 0},
    timeout=10,
)
data = r.json()
Sample response
{
  "data": [
    {
      "bot_id": "call_8f21ab",
      "manager": "anna@acme.com",
      "total_score": 87,
      "checklist_id": "sales_phone_adult",
      "key_result_achieved": true,
      "created_at": "2026-06-22T14:05:11Z"
    }
  ],
  "total": 1284,
  "limit": 50,
  "offset": 0
}
GET /api/v1/calls/{id}

Fetch a single call with its full QA result: score, per-criterion breakdown, summary, strengths and issues.

cURL
curl https://app.meetgrade.com/api/v1/calls/call_8f21ab \
  -H "Authorization: Bearer mg_live_xxx"
Python
import requests

cid = "call_8f21ab"
r = requests.get(
    f"https://app.meetgrade.com/api/v1/calls/{cid}",
    headers={"Authorization": "Bearer mg_live_xxx"},
    timeout=10,
)
call = r.json()
Sample response
{
  "bot_id": "call_8f21ab",
  "manager": "anna@acme.com",
  "created_at": "2026-06-22T14:05:11Z",
  "qa": {
    "total_score": 87,
    "checklist_id": "sales_phone_adult",
    "checklist_name": "Sales · phone",
    "key_result_achieved": true,
    "criteria": {
      "greeting":        { "score": 100, "comment": "Warm, on-brand opening." },
      "needs_discovery": { "score": 70,  "comment": "Probe needs earlier." }
    },
    "summary": "Strong rapport; closing step was vague.",
    "strengths": ["Active listening", "Clear pricing"],
    "issues":    ["No confirmed next step"]
  }
}
criteria is an object keyed by criterion name — { key: { score, comment } } — not an array. On legacy calls checklist_id may be null.
GET /api/v1/checklists

List your scoring checklists with their criteria and weights.

cURL
curl https://app.meetgrade.com/api/v1/checklists \
  -H "Authorization: Bearer mg_live_xxx"
Python
import requests

r = requests.get(
    "https://app.meetgrade.com/api/v1/checklists",
    headers={"Authorization": "Bearer mg_live_xxx"},
    timeout=10,
)
checklists = r.json()["data"]
Sample response
{
  "data": [
    {
      "checklist_id": "sales_phone_adult",
      "name": "Sales · phone",
      "criteria": [
        { "key": "greeting",        "weight": 15 },
        { "key": "needs_discovery", "weight": 25 },
        { "key": "next_step",       "weight": 30 }
      ]
    }
  ]
}

Errors

The API uses standard HTTP status codes. Error bodies are JSON with a human-readable detail field.

StatusMeaning
401Missing, malformed or revoked API key.
404The requested call or resource doesn't exist (or isn't yours).
429Rate limit exceeded — over 120 requests/min. Back off and retry.
{ "detail": "Invalid or revoked API key." }

Webhooks

Instead of polling, let MeetGrade push to you. When a call finishes scoring, we fire a qa_completed event and POST a JSON payload to your configured URL.

Configure your endpoint URL and secret in the app: Settings → Integrations.

Event: qa_completed

Payload
{
  "bot_id": "call_8f21ab",
  "score": 87,
  "manager_email": "anna@acme.com",
  "phone": "+380**********",
  "checklist_id": "sales_phone_adult",
  "key_result_achieved": true,
  "call_url": "https://app.meetgrade.com/call/call_8f21ab"
}

Verifying the signature

Every delivery includes an X-StudyLess-Signature header — an HMAC-SHA256 of the raw request body, keyed with your webhook secret. Recompute it and compare before trusting the payload.

X-StudyLess-Signature: sha256=4f1c...e9a2
Python (Flask)
import hmac, hashlib
from flask import request, abort

WEBHOOK_SECRET = b"your_webhook_secret"

def verify(req):
    sig = req.headers.get("X-StudyLess-Signature", "")
    expected = "sha256=" + hmac.new(
        WEBHOOK_SECRET, req.get_data(), hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(sig, expected)

@app.post("/webhooks/meetgrade")
def handler():
    if not verify(request):
        abort(401)
    event = request.get_json()
    # ... handle qa_completed ...
    return "", 200

Roadmap

🧭

More endpoints are coming — including team and per-manager analytics (aggregate scores, trends, top mistakes). Want early access? Email us at hello@meetgrade.com.