Receiving
- Carrier detection, field locks, sender, photo, damaged flag and custom fields
- Expected packages and purchase orders from CSV, a folder or a URL, with auto-matching
- Bulk receive without barcodes; 2D barcode parsing
Raptool Parcel takes a package from the carrier’s hand to the recipient’s signature: receive it, shelve it, send it out on a delivery route, hand it over and report on it. A web app for the desk, a mobile app that works offline and a PHP API work from the same data.
Seven scenes from the loading dock to the final report. Each one shows the real screen behind it.
A courier hands over the parcels. One scan of the carrier label identifies the carrier, and if the package was expected, the details come from the purchase order or delivery list.
Choose the shelf, add a photo or a damaged flag, print the label. The recipient is told by email and, when you set it up, by text message.
Reminders go out on their own for packages that stay undelivered. If a recipient is away, a rule forwards the package to a cover or holds it until they are back.
A courier scans the route barcode on a handheld and works stop by stop. Several packages can travel together in a pouch to another mailroom.
The recipient signs on the screen, or the courier scans an employee ID card instead. A photo is optional, and every step stays in the package history.
Staff send a package request to a colleague. The mailroom collects it by scanning the label, and from there it follows the normal delivery flow.
Set delivery targets in hours, follow on-time delivery and read the activity log. Run several mailrooms from one install and protect sign-in with a second step.
The parcel moves from the dock to the desk. The web app, the mobile app and the API all work on the same records, so every stop is visible to everyone who needs it.
Direction: dock to desk · illustration
The 1.2 release, grouped the way the mailroom works.
Installation, setup and the API in short. Pick a topic.
Raptool Parcel is plain PHP 8 with MySQL or MariaDB, vanilla JavaScript, no framework, no Composer and no build step.
raptool-parcel.zip anywhere, then double-click install.bat.The installer copies the app to C:\xampp\htdocs\parcel, creates the database and a database user with a random password, writes api/config.php, offers demo data and opens the app. If XAMPP is somewhere else, run install.bat -Xampp D:\xampp. Running it again later upgrades an existing install and keeps your config and data.
raptool-parcel folder to C:\xampp\htdocs\parcel.db/schema.sql, then db/seed.sql.api/config.sample.php to api/config.php and enter the database password. The timezone defaults to Europe/Stockholm.http://localhost/parcel/ and sign in with [email protected] / ChangeMe123. Change the password straight away under Settings, Your account.CREATE DATABASE parcel CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'parcel'@'localhost' IDENTIFIED BY 'choose-a-password';
GRANT ALL ON parcel.* TO 'parcel'@'localhost';
C:\xampp\php\php.exe C:\xampp\htdocs\parcel\db\seed_demo.php
Adds sites, two routes, 14 people, about 130 packages, five staff sign-ins and a second mailroom. The password for all demo staff is Password1.
Keep your config and data. Copy the new files over the old ones, but leave api/config.php in place. Then upgrade the database in one of two ways.
From the server machine, open http://localhost/parcel/upgrade.php. The page runs the database migrator and prints what it did.
C:\xampp\php\php.exe C:\xampp\htdocs\parcel\db\migrate.php
If the migrator has not run you will see “needs upgrade” errors: the database schema is older than the code expects. Run the upgrade again.
Finally, bump the ?v= numbers in web/index.html and mobile/index.html so browsers fetch the new CSS and JS, and bump CACHE in mobile/sw.js so handhelds pick up the new version.
Everything is configured under Settings in the web app. Start with one mailroom and add more as you expand.
Five fixed roles. An admin can limit each user to one or more mailrooms.
| Role | Can do |
|---|---|
| Requester | Sign in, send desk-to-desk package requests, see and print labels for their own, follow delivery status. Least privilege. |
| Viewer | Look at packages and reports only. Cannot take any actions. |
| Courier | Send out, hold, release and deliver (with signature). Can log checkpoints and start routes. |
| Mailroom | Receive, edit, notify, return to sender, reopen. Manage people and forwarding rules. Can set up expected packages. |
| Admin | Everything, including settings, users, mailrooms, and deleting packages. |
Open https://<your-server>/parcel/mobile/ on the device, sign in, and choose Add to home screen or Install app.
LOC-<id> logs your location, ROUTE-<id> starts a route run, POUCH-<id> opens a pouch.Every change goes into a queue on the device and syncs when the connection returns; the home screen shows what is waiting. Anything the server rejects, for example a package someone else already delivered, appears under Sync problems, where it can be retried or discarded.
HTTPS is required for installing the app, the offline cache and the camera. localhost is the only exception.
When a package with a matching tracking or PO number arrives at Receive, an expected package is linked and closed. An expected PO is linked but stays open, so you can receive many packages against one order and close it by hand.
tracking,carrier,sender,recipient,expected,note
SE1234567890,PostNord,Dustin,[email protected],2026-09-25,Urgent
PO-002,DHL,Würth,[email protected],2026-09-26,A pouch is a batch of packages for another mailroom, location or person, sent with a single signature.
Each pouch has a barcode (POUCH-<id>) and a manifest of every package inside.
Staff with the Requester role or higher can send a package request from one person to another inside the building.
INT-<n>.The feature set follows the Wasp Package Tracker 1.2 manual.
| Symptom | What to do |
|---|---|
| “Needs upgrade” errors | The database is older than the code. Open upgrade.php on the server or run db/migrate.php. |
| Cannot install the mobile app, no offline cache or camera | These need HTTPS. Give Apache a certificate; localhost is the only exception. |
| Scanner types but nothing happens | Configure the hardware scanner to send Enter after each scan. |
| New version does not show after upgrade | Bump the ?v= numbers in the two index.html files and CACHE in mobile/sw.js. |
| Item under Sync problems | The server rejected a queued action, for example a package someone else already delivered. Retry or discard it. |
| Emails open in your own mail program | Server email is off by default. Enable Send notifications from the server and fill in SMTP. Microsoft 365 needs SMTP AUTH enabled for the mailbox. |
| Text message failed | A failed text never fails the package action. The failure is logged in the package history. |
| Locked out | Eight failed sign-ins lock an account for 15 minutes. An admin can reset a user’s two-step sign-in under Settings, Users. |
| API answers 401 with a Bearer token sent | If Apache strips the Authorization header, send X-Auth-Token: <token> instead. |
| Reminders do not go out | The tick job runs on page loads, throttled to every 10 minutes. For reliable timing, add a Windows Scheduled Task for api/cron/tick.php. |
Base URL /parcel/api/index.php/. JSON in and out. Send Authorization: Bearer <token> from POST auth/login. Send X-Mailroom: <id> to limit a request to one mailroom. Roles order: requester < viewer < courier < mailroom < admin.
| Method and path | Min role | Purpose |
|---|---|---|
POSTauth/login | none | Sign in; returns a token and the user |
GETbootstrap | viewer | Settings, sites, routes, mailrooms, statuses and version |
GETpackages | viewer | List with status, search, carrier, site, route and date filters |
GETpackages/lookup?tracking= | viewer | Find a package, and its expected match, by tracking number |
GETpackages/{id} | viewer | One package with events, photo and signature |
POSTpackages | mailroom | Receive a package |
PATCHpackages/{id} | mailroom | Edit receive fields or status; logged as an event |
POSTpackages/actions | courier | enroute, hold, release, deliver, return, reopen, transfer, arrive, checkpoint and more |
POSTpackages/notify | mailroom | Build one email per recipient from the template |
POSTpackages/remind | mailroom | Send reminders now |
POSTpackages/bulk | mailroom | Receive 1 to 200 packages at once |
POSTpackages/parse-scan | viewer | Parse a 2D or ANSI MH10.8 scan into tracking, carrier and recipient matches |
GETrecipients/by-badge?badge= | courier | Person and open packages for an ID card |
GETexpected | viewer | Expected packages and purchase orders |
POSTexpected/import | mailroom | Import a CSV of expected items |
GETpouches | viewer | Pouches sent from or addressed to the mailroom |
POSTpouches/{id}/seal | mailroom | Lock a pouch; its packages become en route |
POSTpouches/{id}/deliver | courier | Deliver every package inside with one signature |
POSTroutes/{id}/runs | courier | Start a route run |
PATCHroute-runs/{id} | courier | Record progress or finish a run |
POSTinternal | requester | Create a desk-to-desk request |
GETmailrooms | viewer | Mailrooms the user belongs to |
GETreports/summary | viewer | KPIs, per-day and per-carrier figures, on-time delivery |
GETaudit | admin | Activity log, filterable |
Mobile writes accept an optional client_ref, so a replayed offline action returns the first result and never repeats the work.