This guide provides practical cURL examples for BlueCollar API endpoints.
Base URL used below:
export API_BASE_URL="http://localhost:3000/api"Reusable tokens:
export USER_TOKEN="<user-jwt>"
export CURATOR_TOKEN="<curator-jwt>"
export ADMIN_TOKEN="<admin-jwt>"curl -s http://localhost:3000/healthcurl -X POST "$API_BASE_URL/auth/register" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Ada",
"lastName": "Lovelace",
"email": "ada@example.com",
"password": "Password123!"
}'curl -X POST "$API_BASE_URL/auth/login" \
-H "Content-Type: application/json" \
-d '{
"email": "ada@example.com",
"password": "Password123!"
}'curl "$API_BASE_URL/auth/me" \
-H "Authorization: Bearer $USER_TOKEN"By token in request body:
curl -X PUT "$API_BASE_URL/auth/verify-account" \
-H "Content-Type: application/json" \
-d '{"token":"<verification-token>"}'By token in query:
curl -X PUT "$API_BASE_URL/auth/verify-account?token=<verification-token>"curl -X POST "$API_BASE_URL/auth/forgot-password" \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com"}'curl -X PUT "$API_BASE_URL/auth/reset-password" \
-H "Content-Type: application/json" \
-d '{
"token":"<reset-token>",
"password":"NewPassword123!"
}'curl -X DELETE "$API_BASE_URL/auth/logout" \
-H "Authorization: Bearer $USER_TOKEN"Get redirect response headers:
curl -i "$API_BASE_URL/auth/google"Callback endpoint (normally invoked by Google):
curl -i "$API_BASE_URL/auth/google/callback?code=<google-oauth-code>"List categories:
curl "$API_BASE_URL/categories"Get a category:
curl "$API_BASE_URL/categories/<category-id>"Basic pagination:
curl "$API_BASE_URL/workers?page=1&limit=20"Filter by category and search:
curl "$API_BASE_URL/workers?category=<category-id>&search=plumber"Filter by location:
curl "$API_BASE_URL/workers?city=Lagos&state=Lagos&country=NG"curl "$API_BASE_URL/workers/<worker-id>"curl "$API_BASE_URL/workers/mine?page=1&limit=10" \
-H "Authorization: Bearer $CURATOR_TOKEN"curl -X POST "$API_BASE_URL/workers" \
-H "Authorization: Bearer $CURATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name":"Jane Electric",
"bio":"12 years field experience",
"phone":"+2348012345678",
"email":"jane.electric@example.com",
"walletAddress":"GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"categoryId":"<category-id>"
}'JSON update:
curl -X PUT "$API_BASE_URL/workers/<worker-id>" \
-H "Authorization: Bearer $CURATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Jane Electric Pro"}'Multipart update via method override (file upload):
# Note: This uses the X-HTTP-Method: PUT header to override the POST method.
# HTML forms and multipart/form-data only support GET/POST, so we use POST
# with the X-HTTP-Method header to indicate PUT semantics.
# The API's method-override middleware rewrites this to PUT before routing.
# See API_REFERENCE.md for detailed explanation.
curl -X POST "$API_BASE_URL/workers/<worker-id>" \
-H "Authorization: Bearer $CURATOR_TOKEN" \
-H "X-HTTP-Method: PUT" \
-F "name=Jane Electric Pro" \
-F "avatar=@/path/to/avatar.jpg"curl -X DELETE "$API_BASE_URL/workers/<worker-id>" \
-H "Authorization: Bearer $CURATOR_TOKEN"curl -X PATCH "$API_BASE_URL/workers/<worker-id>/toggle" \
-H "Authorization: Bearer $CURATOR_TOKEN"Get availability:
curl "$API_BASE_URL/workers/<worker-id>/availability"Upsert availability:
curl -X PUT "$API_BASE_URL/workers/<worker-id>/availability" \
-H "Authorization: Bearer $CURATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"weeklySchedule": {
"monday": [{"start":"09:00","end":"17:00"}],
"tuesday": [{"start":"09:00","end":"17:00"}]
}
}'curl -X POST "$API_BASE_URL/workers/<worker-id>/register-on-chain" \
-H "Authorization: Bearer $CURATOR_TOKEN"Create contact request (authenticated user):
curl -X POST "$API_BASE_URL/workers/<worker-id>/contact" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message":"Need urgent wiring repair",
"preferredContact":"email"
}'List worker contact requests (curator):
curl "$API_BASE_URL/workers/<worker-id>/contacts" \
-H "Authorization: Bearer $CURATOR_TOKEN"Update contact request status (curator):
curl -X PATCH "$API_BASE_URL/workers/<worker-id>/contacts/<request-id>" \
-H "Authorization: Bearer $CURATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"status":"accepted"}'Toggle bookmark:
curl -X POST "$API_BASE_URL/workers/<worker-id>/bookmark" \
-H "Authorization: Bearer $USER_TOKEN"List my bookmarks:
curl "$API_BASE_URL/users/me/bookmarks" \
-H "Authorization: Bearer $USER_TOKEN"List reviews:
curl "$API_BASE_URL/workers/<worker-id>/reviews"Create review (authenticated user):
curl -X POST "$API_BASE_URL/workers/<worker-id>/reviews" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rating": 5,
"body": "Great work and on time"
}'Update review (review author):
curl -X PUT "$API_BASE_URL/workers/<worker-id>/reviews/<review-id>" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rating": 4,
"body": "Good work, minor delays"
}'Delete review (review author):
curl -X DELETE "$API_BASE_URL/workers/<worker-id>/reviews/<review-id>" \
-H "Authorization: Bearer $USER_TOKEN"Flag review for moderation (authenticated user):
curl -X PATCH "$API_BASE_URL/workers/<worker-id>/reviews/<review-id>/flag" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason":"inappropriate"}'Get moderation queue (admin):
curl "$API_BASE_URL/workers/<worker-id>/reviews/moderation/queue" \
-H "Authorization: Bearer $ADMIN_TOKEN"Moderate review (admin):
curl -X PATCH "$API_BASE_URL/workers/<worker-id>/reviews/<review-id>/moderate" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"approve"}'Get notification preferences:
curl "$API_BASE_URL/users/me/notifications" \
-H "Authorization: Bearer $USER_TOKEN"Update notification preferences:
curl -X PUT "$API_BASE_URL/users/me/notifications" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"newWorkerNearby": true,
"statusChange": false,
"reviewReply": true,
"announcements": false
}'Get notification history:
curl "$API_BASE_URL/users/me/notifications/history?page=1&limit=20" \
-H "Authorization: Bearer $USER_TOKEN"Mark notification as read:
curl -X PATCH "$API_BASE_URL/users/me/notifications/<notification-id>/read" \
-H "Authorization: Bearer $USER_TOKEN"Mark all notifications as read:
curl -X PATCH "$API_BASE_URL/users/me/notifications/read-all" \
-H "Authorization: Bearer $USER_TOKEN"Save push subscription:
curl -X POST "$API_BASE_URL/users/me/push-subscription" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"endpoint":"https://fcm.googleapis.com/fcm/send/abc",
"keys": {"p256dh":"<key>", "auth":"<auth>"}
}'Delete push subscription:
curl -X DELETE "$API_BASE_URL/users/me/push-subscription" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"endpoint":"https://fcm.googleapis.com/fcm/send/abc"}'Create webhook subscription (curator/admin):
curl -X POST "$API_BASE_URL/webhooks" \
-H "Authorization: Bearer $CURATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhook",
"events": ["worker.created", "worker.updated", "review.created"]
}'List webhook subscriptions (curator/admin):
curl "$API_BASE_URL/webhooks" \
-H "Authorization: Bearer $CURATOR_TOKEN"Get webhook details (curator/admin):
curl "$API_BASE_URL/webhooks/<webhook-id>" \
-H "Authorization: Bearer $CURATOR_TOKEN"Update webhook subscription (curator/admin):
curl -X PUT "$API_BASE_URL/webhooks/<webhook-id>" \
-H "Authorization: Bearer $CURATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhook-v2",
"events": ["worker.created", "worker.deleted"]
}'Delete webhook subscription (curator/admin):
curl -X DELETE "$API_BASE_URL/webhooks/<webhook-id>" \
-H "Authorization: Bearer $CURATOR_TOKEN"Get webhook delivery logs (curator/admin):
curl "$API_BASE_URL/webhooks/<webhook-id>/logs?page=1&limit=50" \
-H "Authorization: Bearer $CURATOR_TOKEN"Retry failed webhook delivery (curator/admin):
curl -X POST "$API_BASE_URL/webhooks/<webhook-id>/logs/<log-id>/retry" \
-H "Authorization: Bearer $CURATOR_TOKEN"Admin stats:
curl "$API_BASE_URL/admin/stats" \
-H "Authorization: Bearer $ADMIN_TOKEN"Paginated workers (admin):
curl "$API_BASE_URL/admin/workers?page=1&limit=25" \
-H "Authorization: Bearer $ADMIN_TOKEN"Paginated users (admin):
curl "$API_BASE_URL/admin/users?page=1&limit=25" \
-H "Authorization: Bearer $ADMIN_TOKEN"Bulk toggle worker active status (admin):
curl -X POST "$API_BASE_URL/admin/workers/bulk-toggle" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workerIds": ["<worker-id-1>", "<worker-id-2>"],
"isActive": true
}'Bulk delete workers (admin):
curl -X DELETE "$API_BASE_URL/admin/workers/bulk-delete" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workerIds": ["<worker-id-1>", "<worker-id-2>"]
}'Bulk update worker category (admin):
curl -X PATCH "$API_BASE_URL/admin/workers/bulk-update" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workerIds": ["<worker-id-1>", "<worker-id-2>"],
"categoryId": "<new-category-id>"
}'Bulk verify workers (admin):
curl -X POST "$API_BASE_URL/admin/workers/bulk-verify" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workerIds": ["<worker-id-1>", "<worker-id-2>"],
"isVerified": true
}'Export workers (CSV):
curl "$API_BASE_URL/admin/export/workers" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-o workers.csvExport users (CSV):
curl "$API_BASE_URL/admin/export/users" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-o users.csvImport workers from CSV:
curl -X POST "$API_BASE_URL/admin/workers/import" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-F "file=@workers.csv"curl -i -X POST "$API_BASE_URL/workers" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Unauthorized Worker","categoryId":"<category-id>"}'Expected error envelope:
{
"status": "error",
"message": "Forbidden",
"code": 403
}curl -i "$API_BASE_URL/auth/me"Expected:
{
"status": "error",
"message": "Unauthorized",
"code": 401
}curl -i -X POST "$API_BASE_URL/auth/register" \
-H "Content-Type: application/json" \
-d '{"email":"invalid","password":"short"}'curl -i "$API_BASE_URL/workers/non-existent-id"Common envelope:
{
"status": "error",
"message": "Worker not found",
"code": 404
}All unexpected server failures follow this envelope:
{
"status": "error",
"message": "Internal server error",
"code": 500
}The project includes an auth rate-limiter configuration in src/config/rateLimiter.ts with defaults:
- window: 15 minutes (
900000ms) - max: 10 requests per IP
- response code:
429
Example 429 envelope:
{
"status": "error",
"message": "Too many requests from this IP, please try again later.",
"code": 429
}Load test example (for auth endpoints where limiter is enabled):
for i in $(seq 1 15); do
curl -s -o /dev/null -w "%{http_code}\n" \
-X POST "$API_BASE_URL/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com","password":"wrong-password"}'
doneInspect standard rate-limit headers:
curl -i -X POST "$API_BASE_URL/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com","password":"wrong-password"}'