Technician check-in flow. Verify location against assigned job site territory when they mark arrival.
Get your API key from fencemaker.app/dashboard/api-keys. Free tier: 1,000 checks/day.
Three options:
• Draw on map at fencemaker.app/dashboard/fences (click "New Fence", trace the job site perimeter)
• Import GeoJSON (upload site boundaries from your scheduling system)
• API creation: POST /api/v1/territories with GeoJSON for bulk setup
Save the returned territory_id (UUID) for each job site — you'll reference this when assigning jobs to technicians.
When technician clicks the button, capture their location and send to Fencemaker for verification. Use browser geolocation API: navigator.geolocation.getCurrentPosition().
GET /api/v1/pip?lat={lat}&lon={lon}&multi=true — returns { matched: true/false, territories: [{ id, name, code }] }. Check that the assigned territory_id is present in the territories array. Log arrival only if matched. Reject false arrivals (prevents check-in fraud).
Configure webhook at fencemaker.app/dashboard/webhooks. When technician arrives, Fencemaker can POST arrival event to your backend for instant dashboard updates or customer notifications.
// Frontend: Web app "I've Arrived" button handler
async function handleArrivalCheckIn(jobSiteId, assignedTerritoryId) {
// Get technician's current location from browser
const position = await new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, {
enableHighAccuracy: true,
timeout: 10000
});
});
const { latitude: lat, longitude: lon } = position.coords;
const response = await fetch('/api/verify-arrival', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jobSiteId, lat, lon })
});
const result = await response.json();
if (result.verified) {
showSuccess('Arrival confirmed! ✓');
} else {
showError('Not at job site yet — try again when you arrive.');
}
}
// Backend: Verify location against Fencemaker territory
app.post('/api/verify-arrival', async (req, res) => {
const { jobSiteId, lat, lon } = req.body;
const assignedTerritoryId = await db.getJobSiteTerritory(jobSiteId);
// Check if technician is inside the assigned territory
const fmRes = await fetch(
`https://fencemaker.app/api/v1/pip?lat=${lat}&lon=${lon}&multi=true`,
{ headers: { 'X-API-Key': process.env.FENCEMAKER_API_KEY } }
);
const data = await fmRes.json();
// Verify the matched territory includes the assigned job site
const inside = data.matched &&
data.territories.some(t => t.id === assignedTerritoryId);
if (!inside) {
return res.status(400).json({
verified: false,
error: 'Location does not match assigned job site'
});
}
await db.logArrival({
jobSiteId,
technicianId: req.user.id,
timestamp: new Date(),
lat, lon,
verified: true
});
res.json({ verified: true });
});This is not automatic background tracking — it requires the technician to click "I've Arrived" in your web app. Web browsers cannot track location in the background when the tab is closed or minimized. For true passive arrival detection (automatic entry/exit without user action), you'll need a native mobile app with background location permissions.