POST a URL, get a human QA report. Integrate TestMyVibes into your CI/CD โ tests run async, results come back fast.
https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1
Every request needs a Bearer token. Grab one from Dashboard → API Keys.
Authorization: Bearer tmv_live_abc123...
Rate limit: 60 req/min per key. Keys available on Pro and Scale plans.
All errors return JSON with error and code fields.
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Missing or malformed fields |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN | Key doesn't have access to this resource |
| 404 | NOT_FOUND | Job, project, or resource doesn't exist |
| 429 | RATE_LIMITED | Too many requests โ slow down |
| 500 | INTERNAL_ERROR | Something broke on our end |
{
"error": "Insufficient credits",
"code": "INSUFFICIENT_CREDITS"
}
/v1/jobs
Submit a test job. Returns a jobId immediately โ tests run async.
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | URL to test |
title | string | Yes | Job title |
description | string | Yes | What should the checker test? |
jobType | string | Yes | form_submission, auth_flow, payment_flow, mobile_responsive, full_user_story, first_impression, custom |
checklistItems | array | No | Custom checklist items [{description, expectedOutcome, severity}]. If omitted, AI generates them. |
priority | string | No | "normal" (default) or "urgent" (2x credits, jumps the queue) |
projectId | string | No | Associate with a project |
slaMinutes | number | No | 15, 30, or 60 (default 60) |
credentials | object | No | {username, password, notes} โ AES-256-GCM encrypted at rest |
generateChecklist | string | No | "sync" or "async" (default). Sync waits for AI generation before responding. |
curl -X POST https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs \
-H "Authorization: Bearer tmv_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"url": "https://myapp.com",
"title": "Test checkout flow",
"description": "Complete a purchase with a test card",
"jobType": "payment_flow",
"priority": "normal"
}'
const res = await fetch('https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs', {
method: 'POST',
headers: {
'Authorization': 'Bearer tmv_live_abc123',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://myapp.com',
title: 'Test checkout flow',
description: 'Complete a purchase with a test card',
jobType: 'payment_flow',
priority: 'normal'
})
});
const data = await res.json();
import requests
res = requests.post(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs",
headers={"Authorization": "Bearer tmv_live_abc123"},
json={
"url": "https://myapp.com",
"title": "Test checkout flow",
"description": "Complete a purchase with a test card",
"jobType": "payment_flow",
"priority": "normal"
}
)
data = res.json()
{
"jobId": "j_abc123",
"status": "pending",
"estimatedCompletionMinutes": 15,
"creditsDeducted": 3,
"checklistItemCount": 8
}
/v1/jobs
List your jobs. Filter by status, project, or date.
| Param | Type | Default | Description |
|---|---|---|---|
status | string | all | pending, claimed, completed, failed |
projectId | string | โ | Filter by project |
limit | number | 20 | 1โ100 |
offset | number | 0 | Pagination offset |
since | string | โ | ISO 8601 date โ only jobs created after this |
curl "https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs?status=completed&limit=10" \
-H "Authorization: Bearer tmv_live_abc123"
const res = await fetch('https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs?status=completed&limit=10', {
headers: { 'Authorization': 'Bearer tmv_live_abc123' }
});
const data = await res.json();
import requests
res = requests.get(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs",
headers={"Authorization": "Bearer tmv_live_abc123"},
params={"status": "completed", "limit": 10}
)
data = res.json()
{
"jobs": [
{
"id": "j_abc123",
"status": "completed",
"title": "Test checkout flow",
"url": "https://myapp.com",
"jobType": "payment_flow",
"createdAt": "2026-03-14T20:30:00Z",
"reportId": "r_def456"
}
],
"total": 42,
"limit": 10,
"offset": 0
}
/v1/jobs/:id
Get a single job's status and metadata.
| Param | Type | Description |
|---|---|---|
id | string | Job ID (e.g. j_abc123) |
curl https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123 \
-H "Authorization: Bearer tmv_live_abc123"
const res = await fetch('https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123', {
headers: { 'Authorization': 'Bearer tmv_live_abc123' }
});
const data = await res.json();
import requests
res = requests.get(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123",
headers={"Authorization": "Bearer tmv_live_abc123"}
)
data = res.json()
{
"id": "j_abc123",
"status": "completed",
"title": "Test checkout flow",
"url": "https://myapp.com",
"jobType": "payment_flow",
"creditsUsed": 3,
"slaMinutes": 60,
"createdAt": "2026-03-14T20:30:00Z",
"claimedAt": "2026-03-14T20:31:00Z",
"completedAt": "2026-03-14T20:42:00Z",
"reportId": "r_def456"
}
/v1/jobs/:id/report
Get the full QA report. Only available once the job is complete.
curl https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123/report \
-H "Authorization: Bearer tmv_live_abc123"
const res = await fetch('https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123/report', {
headers: { 'Authorization': 'Bearer tmv_live_abc123' }
});
const data = await res.json();
import requests
res = requests.get(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123/report",
headers={"Authorization": "Bearer tmv_live_abc123"}
)
data = res.json()
{
"id": "r_def456",
"overallStatus": "fail",
"passCount": 5,
"failCount": 2,
"skipCount": 0,
"checkerSummary": "Checkout flow has two critical issues...",
"items": [
{
"id": "ci_001",
"description": "Submit form with empty email",
"status": "fail",
"checkerNote": "No validation shown โ form submits silently",
"screenshotUrl": "https://storage.example.com/ss_001.png"
},
{
"id": "ci_002",
"description": "Complete purchase with test card",
"status": "pass",
"checkerNote": "Worked perfectly, confirmation page shown"
}
],
"recordingUrl": "https://storage.example.com/rec_001.webm",
"checkerRating": 4.8,
"createdAt": "2026-03-14T20:42:00Z"
}
/v1/jobs/:id/retest
Re-run the same test. No body needed โ we clone the original job.
curl -X POST https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123/retest \
-H "Authorization: Bearer tmv_live_abc123"
import requests
res = requests.post(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/j_abc123/retest",
headers={"Authorization": "Bearer tmv_live_abc123"}
)
data = res.json()
{
"jobId": "j_xyz789",
"parentJobId": "j_abc123",
"status": "pending",
"creditsDeducted": 3
}
/v1/jobs/bulk
Fire up to 20 jobs at once. Perfect for post-deploy smoke tests.
curl -X POST https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/bulk \
-H "Authorization: Bearer tmv_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"jobs": [
{ "url": "https://myapp.com/login", "title": "Test login", "description": "Sign in with test creds", "jobType": "auth_flow" },
{ "url": "https://myapp.com/checkout", "title": "Test checkout", "description": "Complete a purchase", "jobType": "payment_flow" }
]
}'
import requests
res = requests.post(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/bulk",
headers={"Authorization": "Bearer tmv_live_abc123"},
json={
"jobs": [
{"url": "https://myapp.com/login", "title": "Test login", "description": "Sign in", "jobType": "auth_flow"},
{"url": "https://myapp.com/checkout", "title": "Test checkout", "description": "Buy something", "jobType": "payment_flow"}
]
}
)
data = res.json()
{
"batchId": "batch_abc123",
"jobIds": ["j_001", "j_002"],
"totalCreditsDeducted": 5,
"estimatedCompletionMinutes": 20
}
/v1/jobs/bulk/:batchId
Check the status of a bulk job batch.
curl https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/jobs/bulk/batch_abc123 \
-H "Authorization: Bearer tmv_live_abc123"
{
"batchId": "batch_abc123",
"overallStatus": "in_progress",
"totalJobs": 2,
"completedJobs": 1,
"passCount": 1,
"failCount": 0,
"jobs": [
{ "id": "j_001", "status": "completed" },
{ "id": "j_002", "status": "claimed" }
]
}
/v1/projects
List all your projects with stats.
curl https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/projects \
-H "Authorization: Bearer tmv_live_abc123"
import requests
res = requests.get(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/projects",
headers={"Authorization": "Bearer tmv_live_abc123"}
)
data = res.json()
{
"projects": [
{
"id": "p_abc123",
"name": "My SaaS App",
"defaultUrl": "https://myapp.com",
"jobCount": 42,
"passRate": 0.85,
"createdAt": "2026-01-15T10:00:00Z"
}
]
}
/v1/projects
Create a new project. Gets you a deploy hook URL for CI integration.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Project name |
description | string | No | What you're building |
defaultUrl | string | No | Default URL to test |
defaultJobType | string | No | Default job type for new tests |
defaultSlaMinutes | number | No | Default SLA: 15, 30, or 60 |
curl -X POST https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/projects \
-H "Authorization: Bearer tmv_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"name": "My SaaS App",
"defaultUrl": "https://myapp.com",
"defaultJobType": "full_user_story"
}'
import requests
res = requests.post(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/projects",
headers={"Authorization": "Bearer tmv_live_abc123"},
json={
"name": "My SaaS App",
"defaultUrl": "https://myapp.com",
"defaultJobType": "full_user_story"
}
)
data = res.json()
{
"projectId": "p_new123",
"name": "My SaaS App",
"deployHookUrl": "https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/hooks/deploy/dhk_xxxxxxxx"
}
/v1/credits
Check your credit balance, usage, and expiring credits.
curl https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/credits \
-H "Authorization: Bearer tmv_live_abc123"
import requests
res = requests.get(
"https://a41fb9b8-17b6-4c0b-93e5-d95854134fbb-00-2wp9ocxvv9nql.picard.replit.dev/api/v1/credits",
headers={"Authorization": "Bearer tmv_live_abc123"}
)
data = res.json()
{
"available": 47,
"used": 28,
"total": 75,
"plan": "pro",
"expiringCredits": [
{ "amount": 10, "expiresAt": "2026-06-14T00:00:00Z" }
]
}
Get real-time notifications when stuff happens. Set your webhook URL in Project Settings.
| Event | Fires when |
|---|---|
job.created | A new test job is submitted |
job.claimed | A checker picks up the job |
job.completed | Report is ready โ go read it |
job.failed_sla | Job exceeded SLA without completion โ it's been re-queued |
{
"event": "job.completed",
"timestamp": "2026-03-14T20:42:00Z",
"data": {
"jobId": "j_abc123",
"status": "completed",
"reportId": "r_def456",
"overallStatus": "fail",
"passCount": 5,
"failCount": 2
}
}
Every webhook payload is signed with HMAC-SHA256 using your project's webhook secret. Check the X-TMV-Signature header.
const crypto = require('crypto');
const expected = crypto
.createHmac('sha256', process.env.TMV_WEBHOOK_SECRET)
.update(rawBody)
.digest('hex');
if (expected === req.headers['x-tmv-signature']) {
// legit โ process it
}
3 attempts with exponential backoff (1s, 10s, 60s) on non-2xx responses. After 3 failures, the webhook is disabled โ re-enable it from project settings.
Initial API release. 9 endpoints: submit jobs, list jobs, get status, reports, retest, bulk submit, bulk status, projects, credits. Webhook events for full job lifecycle.