Task Manager API documentation
How to authenticate, manage tasks, avoid conflicts and sync offline changes. Every example uses https://global-tech-trial.vercel.app as the base URL.
Overview
The Task Manager API is a JSON REST API for tasks. Successful responses look like { "data": ... } and failures look like { "error": { "message", "details" } }. Everything except sign-in, registration, password reset and /health needs a Bearer token.
It is built by Ado Daniel NJ at iamsupreme developers. You can try every endpoint from the live playground on the home page.
Authentication
Create an account with POST /api/auth/register (email, password of at least 8 characters, optional name) or sign in with POST /api/auth/login. Both return { user, token }. Send the token as Authorization: Bearer <token>. A missing, bad or expired token returns 401.
curl -X POST https://global-tech-trial.vercel.app/api/auth/register \
-H "content-type: application/json" \
-d '{"email":"ada@example.com","password":"correct horse battery staple","name":"Ada"}'
TOKEN=$(curl -s -X POST https://global-tech-trial.vercel.app/api/auth/login \
-H "content-type: application/json" \
-d '{"email":"ada@example.com","password":"correct horse battery staple"}' | jq -r .data.token)Forgot a password? POST /api/auth/forgot-password always answers 200 with the same message, so it never reveals which emails are registered. The emailed token is single-use and expires after one hour. Finish with POST /api/auth/reset-password and { token, password }.
curl -X POST https://global-tech-trial.vercel.app/api/auth/forgot-password \
-H "content-type: application/json" \
-d '{"email":"ada@example.com"}'
# always 200, whether or not that email is registered
curl -X POST https://global-tech-trial.vercel.app/api/auth/reset-password \
-H "content-type: application/json" \
-d '{"token":"<token from the email>","password":"a new strong password"}'Email verification
Registering sends a verification email. You can sign in and read right away with an unverified account, but creating, editing, deleting or syncing tasks needs a verified email first (403 otherwise). The check runs fresh on every request, so verifying takes effect immediately with no re-login required.
The emailed link is a plain GET /api/auth/verify-email?token=..., meant to be clicked: it verifies the account and redirects to a confirmation page. POST /api/auth/verify-email with { token } is the same check for a client that already has the raw token and wants a fresh, verified JWT back directly, as { user, token }. Lost or expired the email? POST /api/auth/resend-verification with { email } sends a new one, answering 200 either way so it never reveals whether that email is registered or already verified. Neither verify-email route is rate-limited: the token is 256 random bits and single-use, so limiting by IP or email would only let an attacker lock out the real owner.
# resend the verification email if the link expired or never arrived
curl -X POST https://global-tech-trial.vercel.app/api/auth/resend-verification \
-H "content-type: application/json" \
-d '{"email":"ada@example.com"}'
# verify with the token from the emailed link
curl -X POST https://global-tech-trial.vercel.app/api/auth/verify-email \
-H "content-type: application/json" \
-d '{"token":"<token from the email>"}'
# { data: { user, token } } — a fresh token, no re-login needed
# the emailed link itself is a plain GET, meant to be clicked, not called from code:
# it redirects a browser straight to a confirmation page instead of returning JSON
# GET https://global-tech-trial.vercel.app/api/auth/verify-email?token=<token from the email>GET /api/auth/me (auth required) returns the caller's own profile, including emailVerified and emailVerifiedAt, so a client can check status without decoding its token or re-logging in.
curl "https://global-tech-trial.vercel.app/api/auth/me" -H "Authorization: Bearer $TOKEN"
# { data: { id, email, name, emailVerified, emailVerifiedAt, createdAt } }Tasks
POST /api/tasks creates a task. Required: title, startTime, endTime (not before the start). Optional: description, parentId, status (todo, inProgress or done), visible.
curl -X POST https://global-tech-trial.vercel.app/api/tasks \
-H "content-type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Ship the release","startTime":"2026-01-01T09:00:00Z","endTime":"2026-01-01T17:00:00Z"}'GET /api/tasks lists your tasks plus everyone's visible ones. Filter with status, creator, parentId, visible, search and a time range, and sort with sort=-startTime. Paginate with offset for numbered pages or cursor for fast keyset pagination on large lists.
curl "https://global-tech-trial.vercel.app/api/tasks?status=todo&sort=-startTime" \
-H "Authorization: Bearer $TOKEN"GET /api/tasks/:id returns one task (404 if it is missing, deleted or hidden from you). DELETE /api/tasks/:id is a soft delete. Only the creator can edit or delete a task (403).
Idempotent creates
Add an Idempotency-Key header to a create. If the connection drops and you resend the request with the same key, you get the original task back (200, not 201) instead of a duplicate. Keys belong to the user, and a key is tied to its first request: the same key with a different body returns 422.
Version-checked edits
Every task has a version. PATCH /api/tasks/:id takes any subset of the create fields plus the version you last saw. If someone else changed the task in the meantime, you get 409 with the current task in error.details.current, so the first edit is never overwritten.
curl -X PATCH https://global-tech-trial.vercel.app/api/tasks/<id> \
-H "content-type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"status":"done","version":3}'Bulk operations
PATCH /api/tasks and DELETE /api/tasks change many of your tasks at once. They are all-or-nothing: every id must be a live task you created, or nothing changes (404 for an unknown id, 403 for someone else's task). Bulk update accepts an optional versions map for per-task version checks and returns 409 if any listed task has moved on. Use {"all":true} to delete all of your own tasks.
curl -X PATCH https://global-tech-trial.vercel.app/api/tasks \
-H "content-type: application/json" -H "Authorization: Bearer $TOKEN" \
-d '{"ids":["t1","t2"],"data":{"status":"done"},"versions":{"t1":3}}'Offline sync
POST /api/sync pushes a batch of create, update and delete operations, applied in order. Each operation's id is its idempotency key, so resending a batch after a lost response re-applies nothing. The response lists accepted, conflicts (stale version, fix and resubmit) and rejected operations (permanent ones should not be retried).
GET /api/sync?cursor=... returns everything that changed since a cursor, including deletes, which is how a deleted task reaches a device that still holds the old copy. This is the API side of an offline-first app. An offline client is not included yet.
curl -X POST https://global-tech-trial.vercel.app/api/sync \
-H "content-type: application/json" -H "Authorization: Bearer $TOKEN" \
-d '{"operations":[{"id":"op-1","operation":"create","entityId":"t1","payload":{...}}]}'
curl "https://global-tech-trial.vercel.app/api/sync?cursor=<cursor>" -H "Authorization: Bearer $TOKEN"Rate limits
Over a limit you get 429 with a Retry-After header.
register: 5 per hour per IP address.login: 5 failed attempts per 15 minutes per email and IP, and 30 per 15 minutes per IP. Only failed logins count.forgot-password: 10 per hour per IP (429) and 3 per hour per email, which still answers200but sends nothing.resend-verification: 10 per hour per IP and 3 per hour per account, so a client can't spam a user's inbox with verification emails.newsletter/subscribe: 10 per hour per IP.auth/me: 60 per minute per account.
Using the API from a website
Servers, mobile apps and curl only need the URL and a token. Websites on other domains can call the API from the browser too: it answers the CORS preflight check and allows the Authorization, Content-Type, Idempotency-Key and X-Request-Id headers. Browser code can read X-Request-Id and Retry-After from responses. Auth is a Bearer token and never a cookie.
Errors and request IDs
Every response carries an X-Request-Id header. Quote it when you report a problem and it can be traced through the logs. GET /health runs a database check and returns 200, or 503 if the database is down or slow.
Common statuses: 400 invalid input, 401 no or bad token, 403 not the creator, 404 not found or hidden, 409 version conflict, 422 reused idempotency key with a different body, 429 rate limited.
Ready to try it? Open the live playground.