Skip to main content

Overview

MechZie uses Socket.io (not raw WebSocket) for all real-time communication. You must use the socket.io-client package — native WebSocket connections will fail.
Do not use raw WebSocket. Socket.io has its own handshake protocol with rooms, namespaces, and automatic reconnection. Install socket_io_client for Flutter or socket.io-client for web.

Connecting

Flutter (Dart)

JavaScript / TypeScript

Authentication

The server verifies the JWT from auth.token on connection. If the token is invalid or expired, the connection is rejected with a connect_error event. On token refresh, disconnect and reconnect with the new token:

Rooms

When connected, the server automatically joins you to rooms based on your identity:

Joining a Job Room

To receive live location updates for an active job, join its room:

Events Reference

Client → Server (Emit)

location:update

Who: Mechanic only (when en_route, arrived, or in_progress) Send GPS position updates. Emit every ~5 seconds while actively on a job.
Rate limit: 60 updates/minute. Exceeding this silently drops updates. The server debounces database writes to every 30 seconds but updates Redis/Valkey immediately for real-time delivery.

job:join

Who: Customer or assigned mechanic Join a job’s tracking room to receive location:updated and job:status events for that job.
Rate limit: 10/minute

job:leave

Who: Customer or assigned mechanic Leave a job’s tracking room. Do this when navigating away from the tracking screen.
Rate limit: 10/minute

Server → Client (Listen)

job:offer

Room: mechanic:{mechanicProfileId} When: A new job is dispatched to nearby mechanics.
The mechanic has a limited window to accept (30–45s depending on dispatch tier). After timeout, the offer moves to the next group of mechanics.

job:taken

Room: mechanic:{mechanicProfileId} When: A job the mechanic was offered has been accepted by another mechanic.

job:offer-revoked

Room: mechanic:{mechanicProfileId} When: The mechanic accepted a different job, so all their other pending offers are superseded. The client should dismiss any remaining offer dialogs.
When a mechanic accepts any job, the server atomically flips their availability to false and supersedes all their other pending offers. The job:offer-revoked event tells the client to remove stale Accept buttons immediately — do not wait for the round timer.

job:status

Room: job:{jobId} or user:{userId} When: Any job status transition occurs.

job:line-item-added

Room: job:{jobId} When: Mechanic adds a part or labor charge during the job.

location:updated

Room: job:{jobId} When: Mechanic’s position is updated (every ~5s during active job).
ETA is calculated as distance / 30 km/h (assumed urban India speed) and cached with a 30s TTL. Use this for the “X min away” display.

payment:failed

Room: user:{userId} When: A Razorpay payment attempt fails.

Call signaling events

Call signaling uses 4 additional socket events: call:accepted, call:declined, call:missed, and call:cancelled (FCM only). See the Voice Calls guide for the full call flow, FCM payloads, and nonce exchange.

Complete Flutter Integration Example

HTTP Fallback for Tracking

If Socket.io is unavailable, you can poll the mechanic’s location via REST:
Response:
HTTP tracking is rate-limited to 1 request every 2 seconds. Prefer Socket.io for real-time updates — it pushes updates every ~5 seconds without polling overhead.