Partner Device Monetization Requirements
Every partner device registration and lookup response (POST /v1/partner/device, POST /v1/partner/devices/batch, GET /v1/partner/device/:id, GET /v1/partner/devices) carries a monetization_status and a structured requirements object — modeled directly on Stripe's account.requirements.currently_due. Instead of silently accepting a registration that can never actually serve ads, the response tells you exactly what's missing and how to fix it.
{
"monetization_status": "blocked",
"requirements": {
"currently_due": [
{
"code": "location_awaiting_device_gps",
"field": "location",
"reason": "awaiting_device_gps",
"message": "This mobile screen has no location yet. Send a GPS fix in the heartbeat (location.lat/lng) and it resolves automatically.",
"doc_url": "https://api.trillboards.com/docs/monetization-requirements#location_awaiting_device_gps"
}
],
"eventually_due": []
}
}
monetization_status values
ready— the screen has its own coordinates AND its venue is classified. Fully monetizable.limited— servable now, but not on every rail: the venue is not yet classified (missing venue taxonomy / floor-price refinement), or the screen has no position of its own yet and is listed in inventory feeds at your fleet's market location (see Location capability).blocked— no rail can serve it: no usable location for any rail, or venue classification permanently failed.
currently_due entries block (or limit) monetization right now. eventually_due entries don't block serving — they improve creative selection / targeting quality and are worth fixing, but there's no rush.
A device is never refused registration for missing location: it is created, and the response says which rails can serve it until a position arrives.
Location capability
Every response also carries location_capability: where the screen's location comes from, and, per rail, whether that rail has the location it needs.
{
"location_capability": {
"position": "fleet_market",
"rails": {
"inventory_feed": { "status": "ready", "location_source": "fleet_market", "reason": null },
"geo_targeted_demand": { "status": "blocked", "location_source": null, "reason": "awaiting_device_gps" },
"visit_attribution": { "status": "blocked", "location_source": null, "reason": "awaiting_device_gps" }
}
}
}
position — precise (the screen or its device has coordinates), fleet_market (no coordinates of its own; your account's declared fleet market location lists it), or none.
| Rail | What it reads | Ready from |
|---|---|---|
inventory_feed | The programmatic player feed, which accepts a fleet market location | The screen's or device's own coordinates (screen, device), or your fleet's declared market location (fleet_market) when it is complete and its state can be expressed as an ISO 3166-2 code |
geo_targeted_demand | Geo-targeted programmatic demand, and the marketplace placement registries that publish a screen's own coordinate | The screen's or device's own coordinates (screen, device) |
visit_attribution | Visit-attribution location data | The screen's own coordinates and a supported country (screen) |
monetization_status is computed over inventory_feed and geo_targeted_demand; visit_attribution is a measurement capability and does not change it.
A blocked rail's reason:
awaiting_device_gps— a mobile screen with no fix yet. Send a GPS fix in the heartbeat (location.lat/location.lng); every rail that needs the screen's own position becomes ready.no_location_provided,city_without_state,geocode_failed— a static screen whose location could not be resolved (see location_unresolvable).screen_position_pending— the device has reported a position and the screen's own coordinates have not been filled from it yet; the next GPS fix fills them.country_unknown— the rail needs the screen's country. Sendlocation.country(ISO 3166-1 alpha-2).country_not_supported— visit-attribution data is not available in the screen's country.
location_awaiting_device_gps
- Field:
location - Blocks monetization: yes (
blocked), orlimitedwhen your account has declared its fleet market location, which lists the screen in inventory feeds until its own fix arrives - Summary: This is a mobile or semi-mobile screen (
mobility_type) with no usable coordinates yet, on either the screen record or the device record.
How to fix: this is self-healing — no separate API call needed. Include a location object with a real GPS fix in the device's heartbeat body:
{
"location": {
"lat": 45.5017,
"lng": -73.5673,
"accuracy_m": 12,
"heading": 180,
"speed_mps": 8.3,
"source": "gps",
"timestamp": 1784800000
}
}
lat/lng (or latitude/longitude) are the only required fields; the rest are optional. The very next heartbeat that includes a valid fix resolves this requirement automatically. Note this is heartbeat-only — location is not read from the device registration/PATCH body's location.lat/lng fields for this particular gate on mobile screens, since a one-time registration-time coordinate goes stale as a moving screen travels.
location_unresolvable
- Field:
location - Blocks monetization: yes (
blocked), orlimitedwhen your account has declared its fleet market location (see Location capability) - Summary: This is a static (non-mobile) screen with no usable coordinates, and what was provided couldn't be geocoded. The
reasonsub-field distinguishes three cases: no_location_provided— nolocation.lat/lng, street address, or city+state was sent at all.city_without_state— only acitywas sent; a city alone cannot be geocoded.geocode_failed— an address was sent but couldn't be resolved to coordinates.
How to fix: on POST/PATCH /v1/partner/device, send location.lat / location.lng directly, or a full street address, or at minimum location.city + location.state.
enrichment_failed
- Field:
venue - Blocks monetization: yes (
blocked) - Summary: Automated venue classification permanently failed for this screen (
enrichment_status: "permanently_failed").
How to fix: verify the location and venue details are accurate and re-save the device. If it fails again, contact support with the device's external_device_id and screen_id.
display_size_missing
- Field:
display - Blocks monetization: no (
eventually_due— servable, just not ideal) - Summary:
display.width/display.height(pixels) were never sent, so creatives can't be sized precisely for this screen.
How to fix: send display.width and display.height in pixels on POST /v1/partner/device (registration) or PATCH /v1/partner/device/:id (update anytime after registration). This is not an automatic/heartbeat field — the SDK must report it explicitly.