Why This Helps

AI assistants generate better code when given complete context. These prompts include Fencemaker's exact API structure, endpoint URLs, payload shapes, and your specific integration pattern โ€” so you get working code on the first try instead of spending time correcting generic examples.

Integration Prompts โ€” one per platform

01
iOS Complete Integration Integration

CLLocationManager setup, geofence registration, entry/exit handling, POST to /track, offline queue, background execution.

โ–ผ
I'm building a Fencemaker geofencing integration for iOS. Generate a complete, production-ready Swift implementation.

## App Context
- App Name: [YOUR_APP_NAME]
- Minimum OS: iOS 15.0
- Use Case: [e.g., delivery zone alerts, territory tracking, idle detection]

## Fencemaker API Details
- Base URL: https://fencemaker.app/api/v1
- Auth Header: X-API-Key: gfnsr_live_...
- Track Endpoint: POST /api/v1/track
- Payload: { "device_id": "DEVICE-001", "lat": 30.27, "lon": -97.74 }
- Response includes "events" array with "entered"/"exited" and "webhook_fired"
- Territories: GET /api/v1/territories (returns GeoJSON features with id, name, code, geometry)
- Webhooks fire server-side automatically on each /track ping

## What to Generate
1. CLLocationManager subclass with "Always" permission request flow
2. Dynamic geofence loading: fetch from GET /api/v1/territories, convert geometry to CLCircularRegion (centroid + bounding radius), register nearest 20 (iOS OS limit), refresh when device moves >10km
3. CLLocationManagerDelegate methods: didEnterRegion, didExitRegion, didUpdateLocations
4. On entry/exit: POST to /api/v1/track with device_id, lat, lon
5. Offline queue: store failed /track calls in Core Data, retry with exponential backoff (10s, 60s, 5m) when network returns
6. Rate limiting: suppress duplicate POSTs for the same device_id + territory within 60s
7. Secure storage: read API key from Keychain, never hardcoded
8. Info.plist entries required for background location

## Code Requirements
- Complete Swift files, not snippets โ€” full class and delegate implementations
- Inline comments on non-obvious logic (Core Data schema, distance calculations)
- Error handling with try/catch and typed errors
- Works when app is force-quit (background modes: location, background-fetch)
- Validate coordinates are in range before every POST

## Output Format
1. LocationManager.swift โ€” full CLLocationManager wrapper
2. TrackingQueue.swift โ€” Core Data offline queue with retry
3. Info.plist additions (XML)
4. AppDelegate changes for background registration

Generate the code now.
02
Android Complete Integration Integration

GeofencingClient, BroadcastReceiver, Foreground Service, POST to /track, offline queue, battery optimization handling.

โ–ผ
I'm building a Fencemaker geofencing integration for Android. Generate a complete, production-ready Kotlin implementation.

## App Context
- App Name: [YOUR_APP_NAME]
- Minimum SDK: Android 10 (API 29)
- Use Case: [e.g., fleet tracking, idle time detection, delivery alerts]

## Fencemaker API Details
- Base URL: https://fencemaker.app/api/v1
- Auth Header: X-API-Key: gfnsr_live_...
- Track Endpoint: POST /api/v1/track
- Payload: { "device_id": "DEVICE-001", "lat": 30.27, "lon": -97.74 }
- Response: { "events": [{ "type": "entered", "territory_code": "ZONE-A", "webhook_fired": true }] }
- Territories: GET /api/v1/territories (paginated list with GeoJSON geometry and id, name, code)

## What to Generate
1. Two-step background location permission flow (ACCESS_FINE_LOCATION first, then ACCESS_BACKGROUND_LOCATION on separate prompt โ€” required for Android 11+)
2. GeofencingClient setup: fetch territories via API, build Geofence objects (circular from GeoJSON centroid + bounding radius), register with PendingIntent to BroadcastReceiver
3. GeofenceBroadcastReceiver: handle GEOFENCE_TRANSITION_ENTER and GEOFENCE_TRANSITION_EXIT, POST to /api/v1/track, work when app is killed
4. Foreground Service with persistent notification for continuous location tracking
5. Offline queue using Room database: store failed /track calls, retry with exponential backoff, batch when network reconnects
6. Rate limiting: suppress duplicate events for same device + geofence within 60s using SharedPreferences timestamps
7. Secure storage: API key in EncryptedSharedPreferences, never hardcoded
8. Manufacturer battery optimization handling: detect Xiaomi/Huawei/Samsung and prompt user to whitelist app

## Code Requirements
- Complete Kotlin files โ€” full class implementations not snippets
- Coroutines for all async work (no callbacks)
- Hilt dependency injection setup
- AndroidManifest.xml permission and service declarations
- Handle GeofenceStatusCodes errors (GEOFENCE_NOT_AVAILABLE on low accuracy, GEOFENCE_TOO_MANY_GEOFENCES)

## Output Format
1. GeofenceManager.kt โ€” GeofencingClient wrapper and registration logic
2. GeofenceBroadcastReceiver.kt โ€” transition handling and API call
3. LocationForegroundService.kt โ€” persistent service with notification
4. TrackingRepository.kt โ€” Room queue with retry logic
5. AndroidManifest.xml additions

Generate the code now.
03
React Native Complete Integration Integration

Cross-platform native bridge, event emitters, permission handling for iOS and Android, unified TypeScript API.

โ–ผ
I'm building a Fencemaker geofencing integration for React Native. Generate a complete, production-ready TypeScript implementation.

## App Context
- App Name: [YOUR_APP_NAME]
- React Native: 0.72+
- Platforms: iOS 15+ and Android 10+
- Use Case: [e.g., territory tracking for sales reps, delivery zone monitoring]

## Fencemaker API Details
- Base URL: https://fencemaker.app/api/v1
- Auth Header: X-API-Key: gfnsr_live_...
- Track Endpoint: POST /api/v1/track
- Payload: { "device_id": "string", "lat": number, "lon": number }
- Territories Endpoint: GET /api/v1/territories (paginated, returns id, name, code, geometry as GeoJSON)
- Simulate endpoint for testing: POST /api/v1/events/simulate

## What to Generate
1. useGeofencing() React hook that wraps the full lifecycle: permission request, geofence fetch, registration, event listening
2. Background fetch: call GET /api/v1/territories on app start, extract circular region from GeoJSON geometry centroid and bounding radius
3. Native geofence registration using react-native-geofencing (or expo-location as fallback)
4. Event listeners via DeviceEventEmitter for onEnter and onExit โ€” fire when app is backgrounded or killed
5. On each event: POST to /api/v1/track with device_id and current coordinates
6. Offline queue: store failed POSTs in AsyncStorage, retry with exponential backoff on reconnect
7. Permission flow: handle both platforms โ€” iOS "Always Allow", Android two-step background location
8. Clean exported API:
   - initGeofencing(apiKey: string, deviceId: string): Promise
   - onZoneEnter(callback: (zone: Zone) => void): () => void
   - onZoneExit(callback: (zone: Zone, dwellSeconds?: number) => void): () => void
   - stopGeofencing(): void

## Code Requirements
- TypeScript with strict types โ€” Zone, GeofenceEvent, TrackPayload interfaces
- Platform-specific permission handling abstracted behind one requestPermissions() call
- Graceful degradation when permissions denied (warn, don't crash)
- Handles the case where user has >20 territories (prioritise nearest on iOS)

## Output Format
1. useGeofencing.ts โ€” main hook
2. GeofencingService.ts โ€” singleton service class
3. OfflineQueue.ts โ€” AsyncStorage retry queue
4. types.ts โ€” shared interfaces
5. package.json additions (required native packages)
6. Setup instructions (linking, permissions for both platforms)

Generate the code now.
04
Flutter Complete Integration Integration

Platform channels, Dart API, iOS and Android native implementations wrapped behind a single Flutter service.

โ–ผ
I'm building a Fencemaker geofencing integration for Flutter. Generate a complete, production-ready Dart implementation.

## App Context
- App Name: [YOUR_APP_NAME]
- Flutter: 3.10+, Dart 3+
- Minimum OS: iOS 15 / Android 10
- Use Case: [e.g., field agent territory tracking, delivery fleet monitoring]

## Fencemaker API Details
- Base URL: https://fencemaker.app/api/v1
- Auth Header: X-API-Key: gfnsr_live_...
- Track Endpoint: POST /api/v1/track
- Payload: { "device_id": "string", "lat": number, "lon": number }
- Response: { "events": [{ "type": "entered"/"exited", "territory_code": "string" }], "territories_inside": ["uuid"] }
- Territories Endpoint: GET /api/v1/territories โ€” returns list with GeoJSON geometry

## What to Generate
1. FencemakerService Dart singleton โ€” manages full geofencing lifecycle
2. Use geofencing package (flutter_background_geolocation or geofence_service) for cross-platform native support
3. On startup: GET /api/v1/territories, parse GeoJSON geometry to extract center coordinate and radius per territory
4. Register territories as native geofences on both platforms
5. Geofence event callbacks: onEnter(territory) and onExit(territory) โ€” work when app is backgrounded
6. On each event: POST to /api/v1/track with device_id, lat, lon using Dio with retry interceptor
7. Offline handling: queue failed requests in Hive or sqflite, replay on connectivity restoration (use connectivity_plus)
8. Permission flow: geolocator package โ€” request "always" for both platforms, handle deniedForever gracefully
9. Background execution: Android Foreground Service, iOS background modes in Info.plist

## Code Requirements
- Null-safe Dart with strong typing โ€” Territory, GeofenceEvent, TrackRequest models
- Riverpod or Provider for state management (geofencing status, current zone)
- Dio HTTP client with interceptors for auth header and retry on 5xx
- Full pubspec.yaml additions

## Output Format
1. fencemaker_service.dart โ€” main singleton
2. territory_repository.dart โ€” API fetch and GeoJSON parsing
3. track_queue.dart โ€” offline queue with Hive
4. models.dart โ€” Territory, GeofenceEvent types
5. pubspec.yaml additions
6. AndroidManifest.xml and Info.plist required changes

Generate the code now.
05
Server-Side Webhook Handler Integration

Receive Fencemaker webhooks, verify HMAC signatures, parse entry/exit events, trigger downstream actions.

โ–ผ
I'm building a server-side webhook handler to receive geofence events from Fencemaker. Generate a complete, production-ready implementation.

## Server Context
- Runtime: [Node.js (Express) / Python (FastAPI or Flask) / Go]
- Language: [JavaScript/TypeScript / Python / Go]
- Use Case: [e.g., SMS alerts on entry, Slack notifications, database logging, dwell violations]

## Fencemaker Webhook Details

### Entry event payload (POST from Fencemaker to your server):
{
  "event": "geofence.entered",
  "timestamp": "2026-05-06T10:45:00.000Z",
  "data": {
    "device_id": "RIDER-042",
    "territory_id": "uuid",
    "territory_name": "East Austin",
    "event_type": "entered",
    "location": { "lat: 30.2672, lon: -97.7431 }
  }
}

### Exit event payload โ€” includes dwell_seconds:
{
  "event": "geofence.exited",
  "timestamp": "2026-05-06T10:59:07.000Z",
  "data": {
    "device_id": "RIDER-042",
    "territory_id": "uuid",
    "territory_name": "East Austin",
    "event_type": "exited",
    "location": { "lat: 30.2672, lon: -97.7431 },
    "dwell_seconds": 847
  }
}

### Signature verification header:
X-Fencemaker-Signature: sha256=  (only on Custom Webhook channel)

### Delivery behaviour:
- Timeout: 5 seconds โ€” return 2xx immediately, process async
- Retries: none from Fencemaker โ€” implement idempotency on your side
- Headers: Content-Type: application/json, User-Agent: Fencemaker-Webhook/1.0

## What to Generate
1. Webhook endpoint: POST /webhooks/fencemaker
2. HMAC-SHA256 signature verification using raw body (not parsed JSON)
3. Idempotency: deduplicate events using event timestamp + device_id + territory_id in Redis (or in-memory cache)
4. Event routing: separate handlers for "entered" and "exited"
5. Dwell violation logic: if event_type == "exited" and dwell_seconds > 600, trigger alert
6. Action on entry: [YOUR_ACTION โ€” e.g., send Twilio SMS, post to Slack, update DB record]
7. Action on exit with dwell: [YOUR_ACTION โ€” e.g., log violation, notify manager]
8. Async processing: return { ok: true } immediately, process in background worker/queue
9. Structured logging: log event_type, device_id, territory_name, dwell_seconds (not raw coordinates in production)
10. Health check: GET /webhooks/health โ€” returns last received event timestamp

## Code Requirements
- Verify against raw bytes before JSON.parse (signature breaks on parsed body)
- Handle missing X-Fencemaker-Signature gracefully (per-territory webhooks don't send it)
- Rate limiting: max 100 webhook requests per minute per device
- Timeout protection: worker must complete within 30s or log and discard

## Output Format
1. webhook.handler.[js/py/go] โ€” complete handler with routing
2. webhook.verify.[js/py/go] โ€” signature verification utility
3. webhook.worker.[js/py/go] โ€” async processor for actions
4. .env.example with required variables (WEBHOOK_SECRET, etc.)
5. Test command using Fencemaker's simulate endpoint:
   curl -X POST https://fencemaker.app/api/v1/events/simulate \
     -H "X-API-Key: YOUR_KEY" \
     -H "Content-Type: application/json" \
     -d '{"territory_id": "UUID", "device_id": "TEST-01", "event_type": "entered"}'

Generate the code now.

Use Case Prompts โ€” one per business scenario

06
Delivery Zone Validation at Checkout Use Case

Address input โ†’ geocode โ†’ PIP check โ†’ show eligibility. Validates serviceability before order is placed.

โ–ผ
I'm building a delivery zone eligibility checker using Fencemaker. Generate a complete implementation.

## Context
- Framework: [React / Vue / Vanilla JS / Next.js]
- Integration point: Checkout page โ€” check if customer address is within delivery zone before accepting order
- Backend language: [Node.js / Python / PHP]

## Fencemaker API Details
- Base URL: https://fencemaker.app/api/v1
- Auth Header: X-API-Key: gfnsr_live_... (server-side only, never expose to browser)

### Option A โ€” Check by coordinates (GET /api/v1/pip):
GET /api/v1/pip?lat=30.27&lon=-97.74
Response: { "matched": true, "territory": { "name": "South Zone", "code": "ZONE-A", "agent_id": "R-001" } }

### Option B โ€” Check by address (POST /api/v1/territory):
POST /api/v1/territory
Body: { "address": "1408 Congress Ave, Austin, TX" }
Response: { "matched": true, "territory_id": "uuid", "territory_code": "ZONE-A", "agent_name": "Marcus T." }

### Batch check for multiple addresses (POST /api/v1/pip/batch):
Body: { "points": [{ "id": "order-1", "lat": 30.27, "lon": -97.74 }, { "id": "order-2", "address": "Congress Ave, Austin" }] }

## What to Generate
1. Frontend component: address input field with autocomplete (use GET /api/v1/search/autocomplete?q=... for suggestions), "Check availability" button, result display ("We deliver here โœ“" or "Outside delivery area โœ— โ€” nearest zone: X")
2. Backend proxy endpoint: POST /api/check-delivery โ€” accepts { address } or { lat, lon }, calls Fencemaker server-side (keeps API key hidden), returns { eligible: bool, zone: string | null, agent: string | null }
3. Loading state during check, error state if API fails (fail open โ€” allow order, flag for manual review)
4. If matched: store territory_code on the order for downstream routing
5. If unmatched: show friendly message, optionally collect email for waitlist

## Code Requirements
- API key must NEVER appear in frontend code โ€” all Fencemaker calls go through your backend proxy
- Debounce address input 400ms before triggering autocomplete
- Cache eligibility result in sessionStorage for 5 minutes (avoid repeated checks as user edits form)
- Validate address is not empty before calling API
- Handle 429 rate limit gracefully (show "Please try again in a moment")

Generate the code now.
07
Territory Assignment for Leads & Requests Use Case

Auto-assign inbound leads, orders, or service requests to the right rep or agent based on location.

โ–ผ
I'm building automatic territory assignment using Fencemaker to route inbound leads and service requests to the correct agent.

## Context
- Backend: [Node.js / Python / PHP / Ruby]
- Trigger: New lead/order arrives (via webhook, form submission, or CRM event)
- Goal: Determine which territory (and agent) the lead's address falls in, then assign it in [YOUR_CRM/SYSTEM]

## Fencemaker API Details
- Base URL: https://fencemaker.app/api/v1
- Auth Header: X-API-Key: gfnsr_live_...

### Territory check by address:
POST /api/v1/territory
Body: { "address": "1408 Congress Ave, Austin, TX" }
Response: {
  "matched": true,
  "territory_id": "uuid",
  "territory_code": "ZONE-A",
  "agent_id": "R-001",
  "agent_name": "Marcus T.",
  "location_name": "Austin East"
}

### Territory check by coordinates:
GET /api/v1/pip?lat=30.27&lon=-97.74
Response: { "matched": true, "territory": { "id": "uuid", "code": "ZONE-A", "agent_id": "R-001" } }

### Batch assignment for bulk imports:
POST /api/v1/pip/batch
Body: { "points": [{ "id": "lead-123", "address": "Congress Ave, Austin" }, { "id": "lead-124", "lat": 30.28, "lon": -97.73 }] }
Response: { "total": 2, "matched": 1, "match_rate": 50, "results": [...] }

## What to Generate
1. assignTerritory(lead) function โ€” accepts { address?, lat?, lon?, leadId } and returns { assigned: bool, agentId, agentName, territoryCode }
2. Unmatched handling: if matched == false, assign to a default queue or fallback agent (configurable)
3. Overlapping territory resolution: use GET /api/v1/pip?multi=true to return all matches, pick smallest territory (most specific) or first match
4. Bulk assignment worker: process CSV or array of leads using POST /api/v1/pip/batch (up to 1,000 per call), write results back to DB
5. Caching: cache territory results per postcode/address for 24h to reduce API calls
6. Webhook integration: if using Fencemaker's track+webhook flow for real-time field agents, reconcile with static assignment on conflict

## Code Requirements
- Retry on 429 with Retry-After header respect
- Log unmatched leads with their coordinates for territory gap analysis (GET /api/v1/overlaps to find coverage gaps)
- Assignment result must include territory_code for audit trail โ€” store on lead record

Generate the code now.
08
Idle Time Violation Detection Use Case

Track dwell time in restricted zones, surface violations when threshold exceeded, alert supervisors.

โ–ผ
I'm building idle time detection for vehicles or field agents using Fencemaker. Generate a complete implementation.

## Context
- Mobile: [Android / iOS / React Native / Flutter]
- Backend: [Node.js / Python]
- Use Case: Detect when vehicles or agents stay too long in a zone (loading dock, customer site, restricted area) and alert supervisors

## How Fencemaker Handles Dwell

Fencemaker automatically tracks dwell time server-side. On exit:
- POST /api/v1/track fires a webhook to your server
- Webhook exit payload includes dwell_seconds:
  {
    "event": "exited",
    "device_id": "RIDER-042",
    "territory_id": "uuid",
    "territory_name": "Loading Dock A",
    "lat: 30.2672, lon: -97.7431,
    "timestamp": "2026-05-06T10:59:07.000Z",
    "dwell_seconds": 847
  }
- dwell_seconds is always present on exit events โ€” it is the authoritative server-side value

## What to Generate

### Mobile (GPS Tracking)
1. Background location service posting to POST /api/v1/track every 30 seconds
2. Device-side entry timer as backup (start on entered event, stop on exited) โ€” use only for UI display, not authoritative
3. Show "In Zone" badge with elapsed time in app UI, updated every minute
4. Alert when device-side timer exceeds threshold (e.g. 8 minutes) as early warning before server confirms

### Server (Violation Logic โ€” webhook handler)
5. Receive POST webhook from Fencemaker on each exit event
6. Violation check: if dwell_seconds > VIOLATION_THRESHOLD (configurable per territory)
7. Violation action:
   - Log to violations table: device_id, territory_id, dwell_seconds, timestamp, severity
   - Send alert to supervisor: [Slack / SMS / Email / Push]
   - If dwell_seconds > SEVERE_THRESHOLD: escalate to manager
8. Dashboard endpoint: GET /violations?since=7d returns violation history per device and territory
9. Use GET /api/v1/events?device_id=X&event_type=exited to backfill missed webhooks

## Code Requirements
- VIOLATION_THRESHOLD and SEVERE_THRESHOLD must be env variables, not hardcoded
- Idempotent violation logging (deduplicate on device_id + territory_id + timestamp)
- dwell_seconds from Fencemaker is authoritative โ€” device-side timer is display only
- Handle case where webhook delivery is delayed (Fencemaker retries 3x: 30s, 60s, 120s)

Generate the code now.
09
Real-Time Customer Alerts on Driver Arrival Use Case

Notify customers via SMS, push, or email when a delivery driver enters their zone.

โ–ผ
I'm building real-time customer arrival alerts using Fencemaker's entry webhooks. Generate a complete implementation.

## Context
- Backend: [Node.js / Python]
- Notification channel: [Twilio SMS / Firebase Push / Email via SendGrid]
- Use Case: When a delivery driver's device enters a customer's delivery zone, notify the customer immediately

## Fencemaker Flow
1. Driver's mobile app posts GPS to POST /api/v1/track every 15-30 seconds
2. Fencemaker evaluates all territory boundaries server-side
3. On zone entry, Fencemaker fires a POST webhook to your server:
   {
     "event": "entered",
     "device_id": "DRIVER-042",
     "territory_id": "uuid",
     "territory_code": "ZONE-A",
     "territory_name": "East Austin",
     "lat: 30.2672, lon: -97.7431,
     "timestamp": "2026-05-06T10:45:00.000Z",
     "org_id": "your-org-uuid"
   }
4. Your server maps territory_code โ†’ customer record โ†’ sends notification

## What to Generate
1. Webhook handler: POST /webhooks/fencemaker โ€” receive entry event, return 200 immediately, process async
2. Customer lookup: given territory_code (or territory_id), query your DB for order/customer associated with that zone
3. Notification dispatch:
   - Twilio SMS: "Your delivery is nearby โ€” DRIVER-042 has entered your area"
   - Firebase push to customer app (if installed)
   - Fallback to email if no push token
4. Deduplication: suppress repeat notifications for same driver + territory within 10 minutes (prevent alert spam if driver oscillates around boundary)
5. Alert history: log sent alerts to DB โ€” device_id, territory_id, customer_id, channel, sent_at
6. Test flow using Fencemaker simulate:
   curl -X POST https://fencemaker.app/api/v1/events/simulate \
     -H "X-API-Key: YOUR_KEY" \
     -d '{"territory_id": "UUID", "device_id": "DRIVER-042", "event_type": "entered"}'
7. Webhook health check: GET /api/v1/webhooks/health returns delivery_rate and failed count for monitoring

## Code Requirements
- Return { ok: true } in <100ms โ€” all notification logic must run async (queue or background job)
- Map territory_code to customer in DB โ€” do not rely on territory_name (can change)
- Rate limit per customer: max 1 alert per territory per hour
- Log failures: if Twilio/Firebase call fails, retry once after 30s, then log and discard
- Handle missing customer gracefully (territory exists but no active order) โ€” log and skip

Generate the code now.
10
Route Compliance Monitoring Use Case

Detect when vehicles deviate from approved zones, log violations, alert operations.

โ–ผ
I'm building route compliance monitoring using Fencemaker to detect when vehicles leave approved zones. Generate a complete implementation.

## Context
- Mobile: [Android / iOS / React Native]
- Backend: [Node.js / Python]
- Use Case: Vehicles must stay within approved transit corridors. Any exit from an approved zone is a compliance violation.

## Fencemaker Approach
Approved corridors are modelled as polygon territories in Fencemaker. "Entering" means the vehicle is compliant. "Exiting" means a violation.

### Track endpoint (mobile โ†’ Fencemaker):
POST /api/v1/track
Body: { "device_id": "TRUCK-07", "lat": 30.27, "lon": -97.74 }
Response: { "events": [{ "type": "exited", "territory_code": "CORRIDOR-1" }], "territories_inside": [] }

### Violation event (Fencemaker โ†’ your server via webhook):
{
  "event": "exited",
  "device_id": "TRUCK-07",
  "territory_name": "Approved Corridor 1",
  "territory_code": "CORRIDOR-1",
  "lat: 30.2672, lon: -97.7431,
  "timestamp": "2026-05-06T10:59:07.000Z",
  "dwell_seconds": 3620
}

## What to Generate

### Mobile
1. Background tracking service: POST /api/v1/track every 20 seconds
2. Local compliance check: if response.territories_inside is empty AND device was previously inside a zone, trigger local "off route" warning UI immediately (don't wait for webhook)
3. Show compliance badge: "On Route โœ“" (green) / "Off Route โœ—" (red) in app UI
4. Escalating in-app alert: if off-route >2 minutes, vibrate and show modal requiring driver acknowledgement

### Server (Violation handler)
5. Webhook endpoint: POST /webhooks/compliance
6. On "exited" event: mark vehicle as non-compliant in DB, log violation record (device_id, corridor, exit_coords, timestamp)
7. Operations alert: Slack message to #compliance-alerts within 30 seconds of exit
8. If vehicle re-enters zone ("entered" event received): mark as compliant, log resolution, note total violation duration
9. Compliance report endpoint: GET /compliance/violations?since=7d โ€” returns violations per vehicle with duration and map coordinates
10. Missed event recovery: poll GET /api/v1/events?device_id=X&event_type=exited&since= every 5 minutes as backup

## Code Requirements
- Violation duration = time between "exited" and next "entered" for same device + territory
- "exited" from one corridor + immediate "entered" to adjacent corridor is not a violation (configure tolerance: <30s gap is a zone transition)
- Store exit lat/lon for mapping violation locations
- GET /api/v1/devices/:id/status to check current zone for any device on demand (operations dashboard)

Generate the code now.
11
Dynamic Pricing Based on Zone Use Case

Look up pricing tier from current or target zone, update UI dynamically as customer moves or enters address.

โ–ผ
I'm building dynamic pricing based on delivery zones using Fencemaker. Generate a complete implementation.

## Context
- Frontend: [React / Vue / Vanilla JS]
- Backend: [Node.js / Python]
- Use Case: Delivery fees vary by zone (e.g., Zone A = โ‚น30, Zone B = โ‚น60, outside = unavailable). Show the correct fee as customer types their address.

## Fencemaker API Details
- Base URL: https://fencemaker.app/api/v1
- Auth: X-API-Key header (server-side only)

### Check zone by address (POST /api/v1/territory):
Body: { "address": "1408 Congress Ave, Austin, TX" }
Response: {
  "matched": true,
  "territory_code": "ZONE-A",
  "territory_id": "uuid",
  "agent_id": "R-001",
  "location_name": "Austin East"
}

### Autocomplete for address input (GET /api/v1/search/autocomplete):
GET /api/v1/search/autocomplete?q=MG+Road
Response: { "results": [{ "label": "Congress Ave, Austin, TX", "lat": 30.2680, "lon": -97.7430 }] }

### Check by coordinates (GET /api/v1/pip?lat=X&lon=Y):
Use when browser geolocation is available for faster lookup

## Pricing Configuration (your side โ€” not in Fencemaker)
Map territory_code โ†’ price in your config or DB:
  ZONE-A: { fee: 30, label: "Express Zone", eta: "30 min" }
  ZONE-B: { fee: 60, label: "Extended Zone", eta: "60 min" }
  null:    { fee: null, label: "Unavailable", eta: null }

## What to Generate
1. Backend proxy: POST /api/zone-fee โ€” accepts { address } or { lat, lon }, calls Fencemaker, returns { fee, label, eta, eligible }
2. Frontend component:
   - Address input with autocomplete (call GET /api/v1/search/autocomplete through your backend proxy)
   - "Use my location" button (browser geolocation โ†’ GET /pip through proxy)
   - Pricing display that updates live: "Delivering to Congress Ave, Austin โ€” โ‚น30 ยท Express ยท ~30 min โœ“"
   - Unavailable state: "Sorry, we don't deliver here yet"
3. Zone badge on checkout: show territory label and fee before payment
4. Cache zone results per address string for 10 minutes in Redis (avoid hammering API during active checkout sessions)
5. Reverse geocode for "use my location": GET /api/v1/geocode/reverse?lat=X&lon=Y to get human-readable address to display

## Code Requirements
- API key on server only โ€” frontend hits your proxy, not Fencemaker directly
- Debounce address input 500ms before calling autocomplete
- Handle "outside all zones" (matched: false) with clear unavailable state, not an error
- Currency and fee amounts must come from your config, not Fencemaker โ€” territory_code is the key

Generate the code now.
12
Web-Based Arrival Detection Use Case

Manual check-in with geofence verification for field teams โ€” no mobile app needed. Frontend button, backend /check call, anti-fraud measures, optional webhook integration.

โ–ผ
I'm building a web-based arrival verification system for field technicians using Fencemaker. Generate a complete implementation.

## Context
- Platform: [React / Next.js / Vue / Vanilla JS + Node.js backend]
- Use Case: Field service company without native mobile app (yet). Technicians use web app on their phones. When they arrive at a job site, they click "I've Arrived" and we verify their location against the assigned geofence before logging arrival.
- Constraint: Web browsers cannot do background location tracking โ€” this is manual check-in with geofence verification, not passive monitoring.

## Fencemaker Endpoint
GET /api/v1/pip?lat={lat}&lon={lon}&multi=true
Headers: X-API-Key: gfnsr_live_...
Response 200 (inside): { "matched": true, "territories": [{ "id": "uuid", "name": "Job Site A", "code": "SITE-A" }], "lat": ..., "lon": ..., "response_ms": 12 }
Response 200 (outside): { "matched": false, "lat": ..., "lon": ..., "response_ms": 8 }
Response 429: Rate limit exceeded

To check if technician is at the assigned job site: call /pip?multi=true, then verify that the assignedTerritoryId is present in the returned territories array.

## What to Generate

### 1. Frontend: Arrival Check-In Button
- Button component: "I've Arrived at Job Site"
- On click: capture current location using `navigator.geolocation.getCurrentPosition()`
- Location options: `{ enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }`
- Show loading state while getting location + verifying
- Handle errors:
  - User denies location permission โ†’ show instructions to enable in browser settings
  - Location timeout โ†’ show "Couldn't get your location. Please try again."
  - Verification failed (outside fence) โ†’ show "You're not at the job site yet. Distance: {X} meters away."
  - Verification succeeded โ†’ show success message, log arrival timestamp

### 2. Backend: Verification Endpoint
POST /api/verify-arrival
Body: { "job_site_id": "job_123", "lat": 30.2672, "lon": -97.7431 }
Response 200: { "verified": true, "arrival_logged": true }
Response 400: { "verified": false, "reason": "outside_territory" }

Implementation:
- Look up which territory_id is assigned to the job_site_id (from database)
- Call Fencemaker GET /api/v1/pip?lat={lat}&lon={lon}&multi=true
- Check if data.matched is true AND assignedTerritoryId appears in data.territories
- If not matched, return 400
- If matched, log arrival:
  - Table: arrivals (id, job_site_id, technician_id, territory_id, lat, lon, verified, timestamp)
  - verified: always true (since we checked)
  - timestamp: server timestamp (cannot trust client clock)
- Return success response

### 3. Database Schema
CREATE TABLE job_sites (
  id UUID PRIMARY KEY,
  name TEXT NOT NULL,
  address TEXT,
  territory_id TEXT NOT NULL,  -- Fencemaker territory UUID
  created_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE arrivals (
  id UUID PRIMARY KEY,
  job_site_id UUID REFERENCES job_sites(id),
  technician_id UUID REFERENCES users(id),
  territory_id TEXT NOT NULL,  -- Fencemaker territory UUID
  lat DECIMAL(10, 8) NOT NULL,
  lon DECIMAL(11, 8) NOT NULL,
  verified BOOLEAN DEFAULT true,
  timestamp TIMESTAMP DEFAULT NOW(),
  UNIQUE(job_site_id, technician_id, DATE(timestamp)) -- prevent duplicate check-ins same day
);

### 4. Optional: Webhook Integration
If Fencemaker webhook is configured:
- On verified arrival, trigger webhook POST to client's backend
- Webhook payload: { "event": "arrival.verified", "job_site_id": "...", "technician_id": "...", "timestamp": "..." }
- Use for: real-time dashboard updates, customer SMS notifications, dispatch alerts

### 5. Anti-Fraud Measures
- Server-side validation only: Never trust client to self-report arrival โ€” always call GET /api/v1/pip from backend and verify territory_id match
- Location freshness: Reject coordinates if browser `coords.timestamp` is >5 minutes old (prevents screenshot replay)
- Duplicate prevention: UNIQUE constraint on (job_site_id, technician_id, date) prevents multiple check-ins same day
- Coordinate logging: Store actual lat/lon even when verified, for audit trail if disputes arise

### 6. UI/UX Considerations
- Permission prompt: Request location permission on first use with clear explanation: "We need your location to verify you're at the job site"
- Loading states:
  - "Getting your location..." (geolocation API call)
  - "Verifying arrival..." (Fencemaker /pip call)
- Error messages:
  - Friendly language: "You don't appear to be at the job site yet. Please try again when you arrive."
  - Recovery action: Show map with job site marker + user's current location to help them navigate
- Success confirmation: "โœ“ Arrival verified at [Job Site Name] โ€” [Timestamp]"

### 7. Progressive Enhancement for Future Native App
Store territory_id in job assignments now. When native mobile app is built later:
- Same territory_id values work for passive background tracking
- Database schema unchanged
- Webhook configuration carries forward
- Only difference: change from manual check-in to automatic entry/exit events

## Code Requirements
- Frontend must handle browser location permission denial gracefully
- Backend must never log arrival without Fencemaker verification (no bypass logic)
- Timestamp must be server-generated (client clock cannot be trusted for payroll/compliance)
- HTTPS required (geolocation API only works on secure origins)

Generate the complete code now: frontend component, backend endpoint, database migrations, and error handling for all edge cases.

Optimization Prompts โ€” reliability and performance

13
Dynamic Zone Loading by Proximity Optimization

Fetch only nearby zones, prioritise registration, refresh when device moves >10km โ€” stays under OS geofence limits.

โ–ผ
I'm building proximity-based geofence loading for my Fencemaker mobile integration. Generate a complete implementation.

## Context
- Platform: [iOS / Android / React Native]
- Problem: I have many territories (50+) but iOS only supports 20 simultaneous geofences and Android 100. I need to dynamically load and register only the nearest zones.

## Fencemaker Territories Endpoint
GET /api/v1/territories โ€” returns paginated list of all territories
Response: {
  "territories": [
    { "id": "uuid", "name": "East Austin", "code": "ZONE-A", "geometry": { "type": "Polygon", "coordinates": [[...]] } }
  ],
  "total": 42, "page": 1, "per_page": 50
}

Note: The API does not filter by proximity server-side โ€” fetch all territories and filter client-side, or paginate and filter.

## What to Generate
1. Fetch all territories from GET /api/v1/territories (paginate if total > per_page), cache in local DB on first launch
2. For each territory's GeoJSON geometry: calculate centroid (average of polygon vertices) and bounding radius (max distance from centroid to any vertex)
3. On location update: compute Haversine distance from device to each territory centroid, sort ascending
4. Register only nearest N (20 on iOS, 30 on Android as conservative limit leaving buffer)
5. Unregister all existing geofences, register new top-N โ€” do this atomically to avoid gaps
6. Refresh trigger: when device moves >10km from the position where last load occurred, re-run steps 3-5
7. Edge case: if device is already inside a zone that is not in top-N (large territory far from centroid), always include it in registration set
8. Cache territories for 1 hour โ€” refresh from API in background, apply on next movement event

## Code Requirements
- Haversine formula for distance (not Euclidean โ€” lat/lon distances are not linear)
- iOS: CLCircularRegion with identifier = territory id (uuid) for easy lookup on event
- Android: Geofence.Builder with requestId = territory id
- Thread-safe: geofence registration must happen on main thread (iOS) โ€” dispatch correctly
- Log when zones are swapped in/out for debugging

Generate the code now.
14
Offline Event Queue with Retry Optimization

Store failed /track calls locally, retry with exponential backoff, deduplicate rapid events โ€” never lose a geofence crossing.

โ–ผ
I'm building an offline event queue for Fencemaker POST /track calls on mobile. Generate a complete implementation.

## Context
- Platform: [iOS (Swift) / Android (Kotlin) / React Native (TypeScript)]
- Problem: Network is unreliable in the field. Failed /track calls must be queued locally and replayed when connectivity returns. No geofence event should be lost.

## Fencemaker Track Endpoint
POST /api/v1/track
Headers: X-API-Key: gfnsr_live_...
Body: { "device_id": "TRUCK-07", "lat: 30.2672, lon: -97.7431 }
Response 200: { "events": [...], "territories_inside": ["uuid"], "response_ms": 12 }
Response 4xx: permanent failure โ€” do not retry
Response 5xx or timeout: transient โ€” retry with backoff
Response 429: { "error": "Rate limit exceeded", "retry_after": 60 } โ€” respect retry_after

## What to Generate
1. QueuedEvent model: { id (uuid), device_id, lat, lon, timestamp (when crossing occurred), attempts, next_retry_at, status }
2. Local persistence:
   - iOS: Core Data entity TrackEvent
   - Android: Room database entity
   - React Native: AsyncStorage with JSON array (or SQLite via expo-sqlite for larger queues)
3. Enqueue: on every geofence entry/exit, always write to queue first, then attempt POST immediately
4. Immediate attempt: if POST succeeds, mark as delivered and remove from queue
5. On failure: increment attempts, calculate next_retry_at with exponential backoff:
   - Attempt 1: retry after 10s
   - Attempt 2: retry after 60s
   - Attempt 3: retry after 5m
   - Attempt 4+: retry after 30m
   - Max attempts: 10 โ€” after that, mark as permanently_failed, keep for logging
6. Background replay: check queue every 60s when network is available, send oldest-first (FIFO)
7. Deduplication: if same device_id + lat + lon + timestamp already in queue, discard duplicate (rapid-fire events from oscillating GPS)
8. Rate limiting guard: max 1 POST per device_id per 30 seconds โ€” suppress and queue the rest
9. Queue size limit: max 1,000 events โ€” on overflow, drop oldest permanently_failed entries first, then oldest pending
10. Network detection: listen for connectivity events to trigger immediate replay when going from offline โ†’ online

## Code Requirements
- Timestamps in queue must be when event actually occurred, not when retry fires (so Fencemaker gets accurate timing)
- FIFO delivery โ€” earlier crossings must be delivered before later ones
- Never delete from queue before confirmed 200 from Fencemaker
- Thread-safe queue access (concurrent reads/writes from location callbacks)

Generate the code now.
15
Battery Optimization for Long-Running Tracking Optimization

Reduce location polling frequency, batch API calls, handle manufacturer-specific restrictions โ€” ship apps that don't drain batteries.

โ–ผ
I'm optimising battery usage in my Fencemaker mobile integration. Generate a complete implementation for long-running background tracking.

## Context
- Platform: [Android / iOS / Both]
- Problem: Continuous GPS + frequent POST /api/v1/track calls drain battery within hours. I need a production strategy for full-day (8-12hr) shift tracking.

## Fencemaker Track Endpoint
POST /api/v1/track
Body: { "device_id": "string", "lat": number, "lon": number }
This is the only GPS data Fencemaker needs โ€” it evaluates all geofences server-side on each ping.

## Adaptive Tracking Strategy โ€” What to Generate

### Polling frequency tiers (implement state machine):
- STATIONARY (speed < 2 km/h, detected via accelerometer): poll every 5 minutes
- SLOW (2-20 km/h): poll every 60 seconds
- FAST (>20 km/h): poll every 20 seconds
- NEAR_BOUNDARY (within 500m of any registered territory boundary): poll every 10 seconds regardless of speed

### iOS-specific optimisations:
1. Use CLLocationManager significant location change (startMonitoringSignificantLocationChanges) for stationary mode instead of continuous GPS
2. Switch to full accuracy (kCLLocationAccuracyBest) only when near territory boundary
3. Use CLVisit monitoring as additional trigger for stationary/moving transitions
4. Background task: call beginBackgroundTask before each /track POST to prevent suspension mid-request

### Android-specific optimisations:
5. FusedLocationProviderClient with dynamic priority: PRIORITY_LOW_POWER (stationary), PRIORITY_BALANCED_POWER (slow), PRIORITY_HIGH_ACCURACY (fast/near boundary)
6. Dynamic LocationRequest.interval: update interval based on motion state
7. Detect motion state via ActivityRecognitionClient (WALKING, IN_VEHICLE, STILL) โ€” update tracking tier accordingly
8. Manufacturer whitelist prompts: detect Xiaomi (MIUI), Huawei (EMUI), Samsung (One UI), OnePlus โ€” show a targeted prompt to exempt app from battery optimisation using the correct deep link per manufacturer

### Shared logic:
9. Boundary proximity check: after each location update, compute distance to nearest territory boundary (from cached territory list). If <500m, switch to NEAR_BOUNDARY tier.
10. POST batching when stationary: buffer up to 3 /track calls and send in one batch using POST /api/v1/track/batch (up to 100 pings per call) to reduce radio wake-ups
11. Adaptive accuracy: reduce GPS accuracy when far from territories โ€” saves significant battery

## Metrics to Log
- Battery level at shift start and end
- Number of GPS fixes per hour
- Number of POST /track calls per hour
- Time spent in each tracking tier

Generate the code now.
โš ๏ธ

Always Review AI-Generated Code

AI assistants are powerful but not perfect. Before shipping to production: test on real devices (simulators miss battery and accuracy issues), verify all endpoint URLs and payload shapes match this docs page, confirm API keys are in environment variables and never in source code, and test background execution by force-quitting your app and crossing a zone boundary.

Alert Channel Prompts

Prerequisites

These prompts assume you've already connected a channel in Alerts & Webhooks. Slack and Telegram fire org-wide on every event โ€” the Custom Webhook channel (covered in prompt 05) fires alongside them and is how you intercept events for the enrichment patterns below.

16
Slack Alerts โ€” Routing, Enrichment & Filtering # Slack

Fencemaker fires raw alerts to one Slack channel. This prompt builds a middleware layer that routes events to different channels by zone, enriches Block Kit messages with business context (driver name, order ID), suppresses low-priority noise, and tags on-call engineers for dwell violations.

โ–ผ
I'm building a Slack alert middleware layer for Fencemaker. Fencemaker already sends raw geofence alerts to one Slack channel โ€” I need a custom webhook handler that intercepts those events and dispatches richer, routed messages. Generate a complete implementation.

## How Fencemaker Slack Alerts Work
Fencemaker sends a formatted Block Kit message to ONE configured Slack Incoming Webhook URL on every geofence event. The message looks like:

  ๐ŸŸข Geofence ENTERED
  Device:   RIDER-042
  Zone:     East Austin
  Time:     Today at 10:45 AM
  Location: View on Map โ†’

This fires for every event, every zone, every device โ€” no filtering, no routing, no business context.

## What I Need Instead
Route events to different Slack channels based on zone or event type.
Add business context (driver name, order ID, customer name) that Fencemaker doesn't have.
Suppress noisy events (e.g. rapid re-entry within 5 minutes).
Tag on-call engineers when dwell violations occur.
Post a richer Block Kit card with more actionable info.

## How to Intercept
In Fencemaker: Alerts & Webhooks โ†’ Custom Webhook โ†’ set URL to MY SERVER endpoint.
Fencemaker POSTs this JSON to my server on every event:

POST https://my-server.com/webhook/fencemaker
Content-Type: application/json
X-Fencemaker-Signature: sha256=<hmac-hex>   // if signing secret is set

{
  "event": "geofence.entered",          // or "geofence.exited"
  "timestamp": "2026-04-28T10:45:00.000Z",
  "data": {
    "device_id":      "RIDER-042",
    "territory_id":   "uuid",
    "territory_name": "East Austin",
    "event_type":     "entered",        // "entered" or "exited"
    "location": { "latitude": 30.2672, "longitude": -97.7431 }
  }
}

Note: dwell_seconds is present on "exited" events only:
  "data": { ..., "event_type": "exited", "dwell_seconds": 847 }

Delivery: 5-second timeout, no retries from Fencemaker. Return 2xx immediately.
Signature header present only if you configured a signing secret in Alerts & Webhooks.

## Slack API Details
I will post to Slack using the Web API (not Incoming Webhooks) so I can target multiple channels.
POST https://slack.com/api/chat.postMessage
Headers: Authorization: Bearer xoxb-YOUR-BOT-TOKEN, Content-Type: application/json

Or use channel-specific Incoming Webhook URLs if I have one per channel:
POST https://hooks.slack.com/services/T.../B.../xxx

## Routing Rules (configurable โ€” store in a config file or DB)
  territory_name contains "Depot"        โ†’ post to #fleet-ops
  territory_name contains "Customer"     โ†’ post to #deliveries
  event_type == "exited" AND dwell_seconds > 600  โ†’ post to #violations + tag @oncall
  All other events                       โ†’ post to #geofence-alerts (default)

## Business Context Enrichment
I have a local DB (or JSON file) mapping device_id to business data:
  RIDER-042 โ†’ { name: "Marcus T.", phone: "+1-512-555-0182", active_order: "ORD-8821", customer: "Sarah K." }

Enrich every Slack message with this context before posting.
If device_id not found in DB: post with "Unknown device" and flag for review.

## What to Generate

### 1. Webhook receiver (Node.js Express or Python FastAPI)
POST /webhook/fencemaker
- Verify X-Fencemaker-Signature if SECRET is set (HMAC-SHA256 over raw body)
- Return { ok: true } immediately (respond before processing)
- Hand off to async processor

### 2. Event deduplication
- Suppress duplicate events: same device_id + territory_id + event_type within 5 minutes
- Store last-seen in Redis (key: "seen:{device_id}:{territory_id}:{event_type}", TTL 300s)
- If duplicate: log and discard โ€” don't post to Slack

### 3. Business context lookup
- Query your DB or JSON map by device_id
- Return enriched device object: { name, phone, active_order, customer }
- Handle missing device gracefully (flag, don't crash)

### 4. Routing logic
- routeEvent(territoryName, eventType, dwellSeconds) โ†’ returns array of Slack targets
- Each target: { webhookUrl or channelId, mentionUsers: ["@oncall"] | [] }
- Read routing rules from a config object (easy to edit without code changes)

### 5. Block Kit message builder
Build a rich Slack Block Kit payload for each event type:

ENTERED event:
  [Header] ๐ŸŸข Geofence ENTERED โ€” East Austin
  [Section] Driver: Marcus T. (RIDER-042) ยท Order: ORD-8821 ยท Customer: Sarah K.
  [Section] Time: 28 Apr 2026, 10:45:00 CDT
  [Actions] [View on Map โ†’] [View Order โ†’] [Call Driver โ†’]

EXITED event (no violation):
  [Header] ๐Ÿ”ด Geofence EXITED โ€” East Austin
  [Section] Driver: Marcus T. ยท Dwell: 14m 7s ยท Order: ORD-8821
  [Actions] [View on Map โ†’] [View Order โ†’]

EXITED event (dwell violation โ€” dwell_seconds > THRESHOLD):
  [Header] โš ๏ธ DWELL VIOLATION โ€” East Austin
  [Section] Driver: Marcus T. ยท Dwell: 47m 12s ยท Threshold: 10 min
  [Context] cc: @oncall
  [Actions] [View on Map โ†’] [View Driver โ†’] [Flag Violation โ†’]

### 6. Slack poster
- Post Block Kit payload to each target channel/webhook
- Handle Slack API errors (channel_not_found, not_in_channel, rate_limited)
- On rate_limited: retry after Retry-After seconds (Slack tier 1 = 1 msg/sec)

### 7. Config file (routing-config.js or routing.yaml)
- DWELL_VIOLATION_THRESHOLD: 600  (seconds)
- DEVICE_DB: path to JSON or DB connection
- ROUTING_RULES: array of { match, channel, mention } objects
- SLACK_BOT_TOKEN or per-channel WEBHOOK_URLS
- FENCEMAKER_SIGNING_SECRET

### 8. Webhook health check
GET /webhook/health โ†’ { status: "ok", last_event: ISO timestamp, events_today: N }
Use with Fencemaker's Send Test button to confirm delivery.

## Code Requirements
- Signature verification must use raw bytes before JSON.parse โ€” parsing first breaks HMAC
- All Slack posting is async โ€” never block the 5-second Fencemaker timeout
- dwell_seconds is only present on "exited" events โ€” always guard before reading
- "View on Map" link: https://www.google.com/maps?q=LAT,LON
- Violation threshold and routing rules must be env/config, not hardcoded
- Log every event: device_id, territory_name, event_type, routed_to, dwell_seconds (if present)

## Output Format
1. webhook.handler.js (or .py) โ€” receiver + deduplication + routing
2. slack.poster.js (or .py) โ€” Block Kit builder + Slack API calls
3. device.db.js (or .py) โ€” device context lookup
4. routing.config.js (or .yaml) โ€” all routing rules and thresholds
5. .env.example โ€” FENCEMAKER_SIGNING_SECRET, SLACK_BOT_TOKEN, DWELL_VIOLATION_THRESHOLD
6. Test command using Fencemaker simulate:
   curl -X POST https://fencemaker.app/api/v1/events/simulate \
     -H "X-API-Key: YOUR_KEY" \
     -H "Content-Type: application/json" \
     -d '{"territory_id": "UUID", "device_id": "RIDER-042", "event_type": "entered"}'

Generate the code now.
17
Telegram Bot โ€” Interactive Commands & Alert Workflows # Telegram

Fencemaker's Telegram bot delivers one-way alerts. This prompt makes it two-way โ€” /status to query a device's current zone, /mute to suppress a noisy zone, /violations for a dwell report, and per-driver personal alerts when they enter their assigned territory.

โ–ผ
I'm extending Fencemaker's Telegram integration with interactive bot commands and custom alert workflows. Generate a complete implementation.

## How Fencemaker Telegram Alerts Work
Fencemaker sends one-way alerts to a linked Telegram chat on every geofence event:

  ๐ŸŸข Geofence ENTERED

  ๐Ÿ“ฑ Device: RIDER-042
  ๐Ÿ“ Zone:   East Austin
  โฐ Time:   28 Apr 2026, 10:45:00
  ๐Ÿ—บ Location: View on Map

These fire automatically โ€” no code required on my side for basic alerts.
Fencemaker's built-in bot commands: /start, /connect <token>, /status (org-level status).

## What I Need Beyond the Built-In Alerts
1. /status DEVICE-ID โ€” query which zone a specific device is currently in
2. /mute ZONE-NAME 30m โ€” suppress alerts from a zone for N minutes (reduce noise)
3. /violations โ€” show dwell violation report for the last 24 hours
4. Per-driver alerts โ€” when a driver enters THEIR assigned territory, message their personal Telegram chat

## Architecture: Two Bots Running Together
Bot A โ€” Fencemaker's native bot (already configured): sends built-in alerts to ops chat.
Bot B โ€” MY custom bot (new): runs on my server, handles commands + custom alert routing.
Both run simultaneously. My bot uses Telegram Bot API directly.

## Telegram Bot API
Base URL: https://api.telegram.org/bot<MY_BOT_TOKEN>/
My bot token: create at @BotFather, get token.

### Send a message:
POST https://api.telegram.org/bot<TOKEN>/sendMessage
Body: { chat_id: CHAT_ID, text: "message", parse_mode: "HTML" }

### Receive commands (two options):
Option A โ€” Long polling: GET /getUpdates?offset=N (simple, no public URL needed)
Option B โ€” Webhook: POST https://api.telegram.org/bot<TOKEN>/setWebhook?url=MY_URL
Implement Option B (webhook) โ€” more reliable for production.

## How My Bot Receives Fencemaker Events
Fencemaker โ†’ Custom Webhook โ†’ my server (same webhook as Slack prompt above, or standalone).
My server receives Fencemaker event โ†’ decides whether/how to post to Telegram via Bot API.

Fencemaker event payload (Custom Webhook channel):
{
  "event": "geofence.entered",
  "timestamp": "2026-04-28T10:45:00.000Z",
  "data": {
    "device_id":      "RIDER-042",
    "territory_id":   "uuid",
    "territory_name": "East Austin",
    "event_type":     "entered",
    "location": { "latitude": 30.2672, "longitude": -97.7431 }
  }
}
On exit events: "data" also contains "dwell_seconds": 847

## Fencemaker API (for command handlers that need to query current state)
Base URL: https://fencemaker.app/api/v1
Auth: X-API-Key: YOUR_FENCEMAKER_KEY

### Get current device status:
GET https://fencemaker.app/api/v1/devices/:device_id/status
Response: { "device_id": "RIDER-042", "territories_inside": ["uuid1"], "last_seen": "ISO timestamp", "location": { "lat": ..., "lon": ... } }

### Get recent events for a device:
GET https://fencemaker.app/api/v1/events?device_id=RIDER-042&event_type=exited&since=2026-04-28T00:00:00Z
Response: array of event objects each with dwell_seconds, territory_name, timestamp

### Simulate an event (for testing):
POST https://fencemaker.app/api/v1/events/simulate
Body: { "territory_id": "UUID", "device_id": "RIDER-042", "event_type": "entered" }

## What to Generate

### 1. Telegram webhook receiver
POST /telegram/webhook
- Receive update from Telegram (message.text starts with /)
- Route to correct command handler
- Return { ok: true } in <1 second

### 2. Command: /status [DEVICE-ID]
Handler: parseDeviceId from message โ†’ GET /api/v1/devices/:id/status โ†’ format reply:

  ๐Ÿ“ RIDER-042 โ€” Marcus T.
  Currently inside: East Austin
  Last seen: 2 minutes ago
  Location: 30.2672, -97.7431 ยท View on Map

If device not found: "โš ๏ธ Device RIDER-042 not found. Check the ID and try again."
If territories_inside is empty: "๐Ÿ“ RIDER-042 โ€” not inside any registered territory. Last seen: X min ago."

### 3. Command: /mute [ZONE-NAME] [DURATION]
Examples: /mute "East Austin" 30m   /mute ZONE-A 2h   /mute all 15m
Handler:
- Parse zone name and duration (support: 5m, 30m, 1h, 2h, 24h)
- Store mute in Redis: key "mute:{territory_name_slug}", value "1", TTL = duration in seconds
- Reply: "๐Ÿ”• Alerts muted for East Austin for 30 minutes. Use /unmute East Austin to restore."

In the Fencemaker webhook handler:
- Before posting any Telegram alert, check Redis for active mute on territory_name
- If muted: skip Telegram post, log "muted" in event log

### 4. Command: /unmute [ZONE-NAME]
- Delete Redis key for that zone
- Reply: "๐Ÿ”” Alerts restored for East Austin."

### 5. Command: /violations [optional: last Xh]
Default: last 24 hours
Handler:
- GET /api/v1/events?event_type=exited&since=24h_ago
- Filter: dwell_seconds > VIOLATION_THRESHOLD (configurable, default 600)
- Format reply:

  โš ๏ธ Dwell Violations โ€” Last 24h

  1. RIDER-042 ยท East Austin
     Dwell: 47m 12s ยท Exited: 10:45 AM

  2. TRUCK-07 ยท North Depot
     Dwell: 1h 23m ยท Exited: 2:10 PM

  Total: 2 violations (threshold: 10 min)

If no violations: "โœ… No dwell violations in the last 24 hours."

### 6. Per-driver personal alerts
Use case: each driver has a personal Telegram chat_id stored in your DB.
When a driver's device enters THEIR assigned territory, message them directly.

Driver DB (JSON or DB table):
  RIDER-042 โ†’ { name: "Marcus T.", telegram_chat_id: 123456789, assigned_territory: "East Austin" }

In Fencemaker webhook handler:
- On "entered" event: look up device_id in driver DB
- If driver.assigned_territory == event.territory_name:
    POST sendMessage to driver.telegram_chat_id:
    "โœ… You've entered your zone: East Austin. Good luck on your shift!"
- If driver enters a DIFFERENT territory (not their own):
    POST to ops chat: "โš ๏ธ RIDER-042 (Marcus T.) entered East Austin โ€” not their assigned zone."

### 7. Mute check middleware
isMuted(territoryName) โ†’ checks Redis โ†’ returns bool
Wrap every Telegram alert dispatch with this check.

### 8. Startup: register webhook with Telegram
On server start:
GET https://api.telegram.org/bot<TOKEN>/setWebhook?url=https://my-server.com/telegram/webhook
Verify with:
GET https://api.telegram.org/bot<TOKEN>/getWebhookInfo

## Code Requirements
- All command handlers must reply within Telegram's 5-second timeout โ€” fetch Fencemaker API async if needed, send "โณ Fetching..." first then edit the message
- /mute and /unmute require auth: only allow commands from pre-approved chat_ids (store in ALLOWED_CHAT_IDS env var)
- /violations fetches from Fencemaker API โ€” cache result for 60 seconds to avoid hammering API on repeated calls
- Telegram parse_mode: "HTML" โ€” use <b>bold</b> and <a href="url">link</a>, not Markdown (more reliable)
- "View on Map" link: https://www.google.com/maps?q=LAT,LON
- All bot tokens and chat IDs in env vars โ€” never hardcoded

## Output Format
1. telegram.webhook.js (or .py) โ€” Telegram update receiver + command router
2. commands/status.js โ€” /status handler
3. commands/mute.js โ€” /mute + /unmute handler
4. commands/violations.js โ€” /violations handler
5. fencemaker.handler.js (or .py) โ€” Fencemaker event receiver + per-driver alerts + mute check
6. driver.db.js (or .py) โ€” driver context store (device_id โ†’ name, chat_id, assigned_territory)
7. .env.example โ€” TELEGRAM_BOT_TOKEN, FENCEMAKER_API_KEY, ALLOWED_CHAT_IDS, VIOLATION_THRESHOLD, REDIS_URL
8. Setup instructions: create bot at @BotFather, register webhook, test with /simulate

Generate the code now.
โš ๏ธ

Always Review AI-Generated Code

Before shipping: verify HMAC signature verification uses raw bytes before JSON.parse. Test the Telegram webhook registration with getWebhookInfo. Confirm dwell_seconds is always guarded before reading โ€” it only exists on exit events. Use Fencemaker's Send Test button and POST /api/v1/events/simulate to trigger real payloads before going live.

Tips for Better Output

๐Ÿ“Œ Be specific about your use case

"Idle time detection for loading docks with 10-minute threshold" generates better code than "geofencing".

๐Ÿ“‹ Request full files, not snippets

AI generates better code when it has full context of imports, class structure, and error handling together.

๐Ÿ” Iterate in steps

Start with "fetch and register geofences", test it, then ask for "add event handling", then "add offline queueing". Don't request everything in one shot.

๐Ÿ” Mention edge cases upfront

"Handle offline mode", "deduplicate rapid events", "work on Xiaomi devices" โ€” put these in the prompt, not in follow-up corrections.

Inline IDE Shortcut

If you're using GitHub Copilot, Cursor, or an inline AI assistant, paste this condensed comment at the top of your file to give it Fencemaker context without a full prompt:

// Fencemaker Geofencing Integration
// Base URL: https://fencemaker.app/api/v1
// Auth: X-API-Key header (from env var โ€” never hardcode)
// Track: POST /api/v1/track  body: { device_id, lat, lon }
// Territories: GET /api/v1/territories  (GeoJSON polygon geometry)
// PIP check: GET /api/v1/pip?lat=X&lon=Y
// Webhooks fire server-side on /track โ€” entry payload has event:"entered", exit adds dwell_seconds
// Platform: [iOS 15+ CLLocationManager / Android GeofencingClient / React Native]
// Requirements: background execution, offline queue, 60s deduplication
// Use case: [YOUR_USE_CASE]