Geofencing REST API for iOS & Android
Fencemaker doesn't ship native mobile SDKs — integration is done directly through the REST API. This keeps the client footprint small and puts you in control of location capture and background execution, using each platform's native location services to gather coordinates and Fencemaker's REST endpoints to evaluate geofences and deliver events.
/api/v1/track endpoint under the hood.iOS Integration (Swift)
Use CoreLocation to capture device location, then POST updates to the Fencemaker REST API.
import CoreLocation
// Send a location update to Fencemaker
func sendLocationUpdate(deviceId: String, lat: Double, lon: Double) {
var request = URLRequest(url: URL(string: "https://fencemaker.app/api/v1/track")!)
request.httpMethod = "POST"
request.setValue("gfnsr_live_YOUR_KEY", forHTTPHeaderField: "X-API-Key")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: Any] = ["device_id": deviceId, "lat": lat, "lon": lon]
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
URLSession.shared.dataTask(with: request).resume()
} Location capture and background permissions (NSLocationWhenInUseUsageDescription / NSLocationAlwaysAndWhenInUseUsageDescription) are handled entirely by your app via
CoreLocation — Fencemaker only receives the coordinates you choose to send.
Android Integration (Kotlin)
Use FusedLocationProviderClient to capture device location, then POST updates to the same REST endpoint.
fun sendLocationUpdate(deviceId: String, lat: Double, lon: Double) {
val client = OkHttpClient()
val json = """{"device_id":"$deviceId","lat":$lat,"lon":$lon}"""
val body = json.toRequestBody("application/json".toMediaType())
val request = Request.Builder()
.url("https://fencemaker.app/api/v1/track")
.addHeader("X-API-Key", "gfnsr_live_YOUR_KEY")
.post(body)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) { /* handle events[] in response body */ }
override fun onFailure(call: Call, e: IOException) { /* handle error */ }
})
} Location capture and background permissions (ACCESS_FINE_LOCATION / ACCESS_BACKGROUND_LOCATION) are handled by your app via FusedLocationProviderClient — Fencemaker
only receives the coordinates you choose to send.
What comes back
Every /api/v1/track call evaluates the device against all of your active geofences and returns any entry/exit events inline, in addition to firing configured webhooks:
{
"device_id": "device_001",
"events": [
{ "type": "entered", "territory_code": "ZONE-A", "webhook_fired": true }
],
"territories_inside": ["uuid"],
"response_ms": 12
} iOS vs Android at a Glance
| Consideration | iOS | Android |
|---|---|---|
| Location capture | CoreLocation (CLLocationManager) | FusedLocationProviderClient |
| Background execution | Managed by your app (background modes / significant-location-change) | Managed by your app (foreground service or WorkManager) |
| Event delivery | Server-side webhook (Slack, Telegram, or custom HTTPS) — not a device callback | Server-side webhook (Slack, Telegram, or custom HTTPS) — not a device callback |
| Rate limiting | Batch/throttle updates client-side to stay within API rate limits | Batch/throttle updates client-side to stay within API rate limits |
Integration Notes
Because there's no SDK, your app owns background location handling, permission prompts, and update throttling directly — Fencemaker's role is the REST API: creating geofences, accepting location updates, and delivering entry/exit events as webhooks. Full endpoint and authentication details are in the API reference; free-tier limits for testing this integration are on the free geofencing API page.