Parcel tracking for 30+ South African and international couriers (SAPO, Aramex, The Courier Guy, PostNet, DHL, …) as one Bearer-authenticated JSON API.
Pointing an AI agent at this API?
Hand it the LLM-ready Markdown version — self-contained instructions an agent can follow with just a URL and an API key.
All endpoints live under `https://fujugz4e.vibecode.cloud/api/v1`. `https://fujugz4e.vibecode.cloud` is the origin you were given (scheme + host, e.g. `https://example.com`). Do not add a trailing slash.
Every endpoint requires an API key sent as a Bearer token: `Authorization: Bearer sk_your_key_here`. Keys always start with `sk_`. A missing or invalid key returns `401 { "error": "Invalid or missing API key" }`. Create keys in the app under Profile → API Keys.
Responses are JSON unless noted (file download returns raw bytes). Request bodies are JSON (`Content-Type: application/json`) except file upload, which is `multipart/form-data`.
Requests are rate limited per API key. When you exceed a limit you get `429` (or `403` if the limit is configured to block) with an `error` message and, when applicable, a `Retry-After` header (seconds). Back off and retry.
Errors are JSON with an `error` string and a matching HTTP status (`400` bad input, `401` unauthenticated, `403` forbidden, `404` not found, `413` payload too large, `429` rate limited, `500` server error).
Your base URL is https://fujugz4e.vibecode.cloud. Create API keys under Profile → API Keys.
/api/v1/carriersReturns every courier TrackMyParcel can track. Use the `uuid` as the `:carrier` path segment of `GET /api/v1/track/:carrier/:code`. `region` is `za` (South African courier) or `intl`; `codeHint` describes what a tracking number of that courier looks like.
Request
curl https://fujugz4e.vibecode.cloud/api/v1/carriers \
-H "Authorization: Bearer sk_your_key_here"Response
{
"carriers": [
{ "uuid": "sapo", "name": "South African Post Office (SAPO)", "region": "za", "codeHint": "e.g. RD123456789ZA, PE123456789ZA", "website": "https://www.postoffice.co.za" },
{ "uuid": "thecourierguy", "name": "The Courier Guy", "region": "za", "codeHint": "Waybill / tracking reference", "website": "https://www.thecourierguy.co.za" }
]
}/api/v1/track/:carrier/:codeFetches the live tracking history of one parcel from the courier and returns it normalised: an overall `status`, the courier wording of the latest status, and all scan `events` newest first (ISO 8601 dates, SAST +02:00 when the courier gives local time). Results are cached for up to 10 minutes; add `?refresh=1` to force a new courier lookup. A lookup can take up to ~60 s when the courier is slow.
| Name | In | Type | Req. | Description |
|---|---|---|---|---|
| carrier | path | string | yes | Courier uuid from GET /api/v1/carriers, e.g. `sapo`, `aramex`, `thecourierguy`, `dhl`. |
| code | path | string | yes | Tracking / waybill number. Spaces are ignored, case-insensitive. URL-encode it. |
| refresh | query | "1" | no | Bypass the 10-minute cache. |
Request
curl https://fujugz4e.vibecode.cloud/api/v1/track/sapo/PE664820353ZA \
-H "Authorization: Bearer sk_your_key_here"Response
{
"carrier": "sapo",
"code": "PE664820353ZA",
"ok": true,
"status": "delivered",
"statusText": "Delivered",
"events": [
{ "date": "2023-05-02T11:04:00+02:00", "location": "PRETORIA", "status": "Delivered" },
{ "date": "2023-05-02T07:15:00+02:00", "location": "PRETORIA", "status": "Out for delivery" }
],
"origin": null,
"destination": null,
"source": "SAPO track & trace",
"officialUrl": "https://trackingnew.postoffice.co.za/?ParcelId=PE664820353ZA",
"fetchedAt": "2026-10-01T12:00:00.000Z"
}/api/v1/healthConfirms the API is up and your key is valid. Handy as a first call to verify credentials and connectivity.
Request
curl https://fujugz4e.vibecode.cloud/api/v1/health \
-H "Authorization: Bearer sk_your_key_here"Response
{
"status": "healthy",
"timestamp": "2026-07-19T12:00:00.000Z",
"uptime": 1234.56,
"version": "1.0.0",
"apiKey": "My key",
"userId": "usr_...",
"message": "API is running successfully"
}/api/v1/statsReturns the calling user together with API-usage counters (requests today / this week / this month, error rate, API-key count).
Request
curl https://fujugz4e.vibecode.cloud/api/v1/stats \
-H "Authorization: Bearer sk_your_key_here"Response
{
"user": { "id": "usr_...", "email": "you@example.com", "name": "You", "role": "user", "createdAt": "..." },
"apiStats": {
"totalApiKeys": 2,
"requestsToday": 14,
"requestsThisWeek": 98,
"requestsThisMonth": 412,
"errorRate": "1.20%",
"errorCount": 5
},
"meta": { "timestamp": "...", "apiKey": "My key" }
}/api/v1/usersLists users. A regular key returns only its own user record; an admin key returns all users with pagination.
| Name | In | Type | Req. | Description |
|---|---|---|---|---|
| limit | query | integer | no | Page size, 1–100 (default 10). Admin only; ignored for non-admins. |
| offset | query | integer | no | Rows to skip (default 0). Admin only. |
Request
curl "https://fujugz4e.vibecode.cloud/api/v1/users?limit=20&offset=0" \
-H "Authorization: Bearer sk_your_key_here"Response
{
"users": [
{ "id": "usr_...", "email": "you@example.com", "name": "You", "role": "user", "emailVerified": null, "createdAt": "..." }
],
"meta": { "limit": 20, "offset": 0, "total": 1, "apiKey": "My key" }
}/api/v1/usersAdmin-only endpoint scaffold for creating a user. Ships as a stub in this starter — it validates input and echoes it back rather than persisting. Fill in real creation logic before relying on it.
| Name | In | Type | Req. | Description |
|---|---|---|---|---|
| body | string | yes | New user email. | |
| name | body | string | yes | New user display name. |
| role | body | string | no | 'user' (default) or 'admin'. |
Request
curl -X POST https://fujugz4e.vibecode.cloud/api/v1/users \
-H "Authorization: Bearer sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{"email":"new@example.com","name":"New User","role":"user"}'Response
{
"message": "User creation endpoint - implementation needed",
"requestedData": { "email": "new@example.com", "name": "New User", "role": "user" },
"apiKey": "My key"
}/api/v1/filesUploads a file and stores its raw bytes. Use this instead of a form/Server Action for any real upload (Server Actions cap the body at ~1MB; this endpoint does not). Send `multipart/form-data` with a single `file` field.
| Name | In | Type | Req. | Description |
|---|---|---|---|---|
| file | form | file | yes | The file to upload (multipart field name must be "file"). |
Request
curl -X POST https://fujugz4e.vibecode.cloud/api/v1/files \
-H "Authorization: Bearer sk_your_key_here" \
-F "file=@./photo.png"Response
{
"id": "fil_...",
"filename": "photo.png",
"url": "/api/v1/files/fil_..."
}/api/v1/files/:idStreams the raw file bytes with the stored Content-Type. Because it is Bearer-gated you cannot put it directly in an `<img src>`; fetch it with the token and build an object URL client-side.
| Name | In | Type | Req. | Description |
|---|---|---|---|---|
| id | path | string | yes | File id returned by the upload endpoint. |
Request
curl https://fujugz4e.vibecode.cloud/api/v1/files/fil_your_file_id \
-H "Authorization: Bearer sk_your_key_here" \
--output downloaded-fileResponse
Raw binary body with the stored `Content-Type` and `Content-Disposition: inline; filename="..."`. Returns `404 { "error": "File not found" }` if unknown./api/v1/files/:idDeletes a file owned by the calling key.
| Name | In | Type | Req. | Description |
|---|---|---|---|---|
| id | path | string | yes | File id to delete. |
Request
curl -X DELETE https://fujugz4e.vibecode.cloud/api/v1/files/fil_your_file_id \
-H "Authorization: Bearer sk_your_key_here"Response
{ "deleted": true } // { "deleted": false } with status 404 if not found / not owned