fencemaker
HomePricingUse CasesMigrate from RadarLive DemoQuickstartIntegrate with Android/iOS NEWPrompts for AI NEWMCP NEWDocsOperations Portal
Fencemaker API

Arrival detection with geofence verification

Technician check-in flow. Verify location against assigned job site territory when they mark arrival.

1

Create a Fencemaker account

Get your API key from fencemaker.app/dashboard/api-keys. Free tier: 1,000 checks/day.

2

Create territories for your job sites

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.

3

Add "I've Arrived" button in your web app

When technician clicks the button, capture their location and send to Fencemaker for verification. Use browser geolocation API: navigator.geolocation.getCurrentPosition().

4

Call /pip to verify they're at the job site

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).

5

Optional: Fire webhook for real-time notifications

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 });
});

Watch out:

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.