Reports

5 endpoints

Delivery, geofence and survey figures — the same numbers the dashboard's Reports show. Every report takes a date range (start/end, Y-m-d, days in your workspace's time zone; the last 30 days by default, up to 366) and the dashboard's filters. The only scope a Production token has before customer services turns the rest on.

Get the summary#

GET/reports/summary
Needs reports:read

Totals for the range — deliveries, distinct devices reached, geofence entries and exits, matching campaigns and how many are active now, and registered devices — plus the same counts for each day.

Query parameters

start
string (date)
end
string (date)
campaign
string (uuid)
location
string (uuid)
location_group
string (uuid)
activation
string
One of: on_enter, on_exit, fixed_time
campaign_status
string
One of: active, scheduled, paused, ended
content_type
string
One of: message, survey

Responses

200
200 response
{
  "data": {
    "totals": {
      "delivered": 0,
      "devices_reached": 0,
      "geofence_entries": 0,
      "geofence_exits": 0,
      "campaigns": 0,
      "active_campaigns": 0,
      "registered_devices": 0
    },
    "daily": [
      {
        "date": "string",
        "delivered": 0,
        "devices_reached": 0,
        "geofence_entries": 0,
        "geofence_exits": 0
      }
    ]
  },
  "meta": {
    "start": "string",
    "end": "string",
    "timezone": "string"
  }
}
Response fields
data
object
required
data.totals
object
required
data.totals.delivered
integer
required
data.totals.devices_reached
integer
required
data.totals.geofence_entries
integer
required
data.totals.geofence_exits
integer
required
data.totals.campaigns
integer
required
data.totals.active_campaigns
integer
required
data.totals.registered_devices
integer
required
data.daily
object[]
required
data.daily[].date
string
required
data.daily[].delivered
integer
required
data.daily[].devices_reached
integer
required
data.daily[].geofence_entries
integer
required
data.daily[].geofence_exits
integer
required
meta
object
required
meta.start
string
required
meta.end
string
required
meta.timezone
string
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilitywrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
422

Something in the request isn't valid. fields says what, with the dashboard's wording.

validation_failed
  • validation_failed

    The given data was invalid.

422 response
{
  "error": {
    "code": "validation_failed",
    "message": "The given data was invalid.",
    "fields": {
      "name": [
        "The name field is required."
      ]
    }
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl 'https://api.bubbl.tech/platform/v1/reports/summary' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/reports/summary', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'GET',
    'https://api.bubbl.tech/platform/v1/reports/summary',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bubbl.tech/platform/v1/reports/summary', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);

Report on campaigns#

GET/reports/campaigns
Needs reports:read

One row per matching campaign: its status, type, how many locations it targets, deliveries in the range, and engagement (devices reached ÷ registered devices, as a percentage).

Query parameters

start
string (date)
end
string (date)
campaign
string (uuid)
location
string (uuid)
location_group
string (uuid)
activation
string
One of: on_enter, on_exit, fixed_time
campaign_status
string
One of: active, scheduled, paused, ended
content_type
string
One of: message, survey
status
string
One of: active, scheduled, paused, ended, idle, unused

Responses

200
200 response
{
  "data": [
    {
      "id": "string",
      "name": "string",
      "status": "active",
      "type": "geo",
      "targets": 0,
      "delivered": 0,
      "engagement": 0
    }
  ],
  "meta": {
    "start": "string",
    "end": "string",
    "timezone": "string"
  }
}
Response fields
data
object[]
required
data[].id
string
required
data[].name
string
required
data[].status
string
required
One of: active, scheduled, paused, ended
data[].type
string
required
One of: geo, push
data[].targets
integer
required
data[].delivered
integer
required
data[].engagement
number
required
meta
object
required
meta.start
string
required
meta.end
string
required
meta.timezone
string
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilitywrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
422

Something in the request isn't valid. fields says what, with the dashboard's wording.

validation_failed
  • validation_failed

    The given data was invalid.

422 response
{
  "error": {
    "code": "validation_failed",
    "message": "The given data was invalid.",
    "fields": {
      "name": [
        "The name field is required."
      ]
    }
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl 'https://api.bubbl.tech/platform/v1/reports/campaigns' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/reports/campaigns', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'GET',
    'https://api.bubbl.tech/platform/v1/reports/campaigns',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bubbl.tech/platform/v1/reports/campaigns', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);

Report on locations#

GET/reports/locations
Needs reports:read

One row per matching location: whether an active campaign targets it, its groups, geofence entries and exits in the range, engagement (devices that entered ÷ registered devices, as a percentage) and the average dwell in minutes (null when no entry was followed by an exit).

Query parameters

start
string (date)
end
string (date)
campaign
string (uuid)
location
string (uuid)
location_group
string (uuid)
activation
string
One of: on_enter, on_exit, fixed_time
campaign_status
string
One of: active, scheduled, paused, ended
content_type
string
One of: message, survey
status
string
One of: active, scheduled, paused, ended, idle, unused

Responses

200
200 response
{
  "data": [
    {
      "id": "string",
      "name": "string",
      "status": "active",
      "groups": [
        "string"
      ],
      "entries": 0,
      "exits": 0,
      "engagement": 0,
      "dwell_minutes": 0
    }
  ],
  "meta": {
    "start": "string",
    "end": "string",
    "timezone": "string"
  }
}
Response fields
data
object[]
required
data[].id
string
required
data[].name
string
required
data[].status
string
required
One of: active, idle
data[].groups
string[]
required
data[].entries
integer
required
data[].exits
integer
required
data[].engagement
number
required
data[].dwell_minutes
number | null
required
meta
object
required
meta.start
string
required
meta.end
string
required
meta.timezone
string
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilitywrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
422

Something in the request isn't valid. fields says what, with the dashboard's wording.

validation_failed
  • validation_failed

    The given data was invalid.

422 response
{
  "error": {
    "code": "validation_failed",
    "message": "The given data was invalid.",
    "fields": {
      "name": [
        "The name field is required."
      ]
    }
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl 'https://api.bubbl.tech/platform/v1/reports/locations' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/reports/locations', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'GET',
    'https://api.bubbl.tech/platform/v1/reports/locations',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bubbl.tech/platform/v1/reports/locations', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);

Report on notifications#

GET/reports/notifications
Needs reports:read

One row per matching notification: its status (from the campaigns it's on, or unused), type, sent (delivered plus failed push sends) and delivered in the range, and reach (devices reached ÷ registered devices, as a percentage).

Query parameters

start
string (date)
end
string (date)
campaign
string (uuid)
location
string (uuid)
location_group
string (uuid)
activation
string
One of: on_enter, on_exit, fixed_time
campaign_status
string
One of: active, scheduled, paused, ended
content_type
string
One of: message, survey
status
string
One of: active, scheduled, paused, ended, idle, unused

Responses

200
200 response
{
  "data": [
    {
      "id": "string",
      "name": "string",
      "status": "active",
      "type": "message",
      "sent": 0,
      "delivered": 0,
      "reach": 0
    }
  ],
  "meta": {
    "start": "string",
    "end": "string",
    "timezone": "string"
  }
}
Response fields
data
object[]
required
data[].id
string
required
data[].name
string
required
data[].status
string
required
One of: active, scheduled, paused, ended, unused
data[].type
string
required
One of: message, survey
data[].sent
integer
required
data[].delivered
integer
required
data[].reach
number
required
meta
object
required
meta.start
string
required
meta.end
string
required
meta.timezone
string
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilitywrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
422

Something in the request isn't valid. fields says what, with the dashboard's wording.

validation_failed
  • validation_failed

    The given data was invalid.

422 response
{
  "error": {
    "code": "validation_failed",
    "message": "The given data was invalid.",
    "fields": {
      "name": [
        "The name field is required."
      ]
    }
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl 'https://api.bubbl.tech/platform/v1/reports/notifications' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/reports/notifications', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'GET',
    'https://api.bubbl.tech/platform/v1/reports/notifications',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bubbl.tech/platform/v1/reports/notifications', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);

Report on surveys#

GET/reports/surveys
Needs reports:read

One row per survey deployment (a survey notification on a campaign): the campaign and survey, what triggers it, how many questions it asks, and how many devices responded in the range.

Query parameters

start
string (date)
end
string (date)
campaign
string (uuid)
location
string (uuid)
location_group
string (uuid)
activation
string
One of: on_enter, on_exit, fixed_time
campaign_status
string
One of: active, scheduled, paused, ended
content_type
string
One of: message, survey
status
string
One of: active, scheduled, paused, ended, idle, unused

Responses

200
200 response
{
  "data": [
    {
      "id": "string",
      "campaign_id": "string",
      "campaign_name": "string",
      "survey_id": "string",
      "survey_name": "string",
      "trigger_type": "on_enter",
      "questions": 0,
      "responses": 0,
      "status": "active"
    }
  ],
  "meta": {
    "start": "string",
    "end": "string",
    "timezone": "string"
  }
}
Response fields
data
object[]
required
data[].id
string
required
data[].campaign_id
string
required
data[].campaign_name
string
required
data[].survey_id
string
required
data[].survey_name
string
required
data[].trigger_type
string
required
One of: on_enter, on_exit, fixed_time
data[].questions
integer
required
data[].responses
integer
required
data[].status
string
required
One of: active, scheduled, paused, ended
meta
object
required
meta.start
string
required
meta.end
string
required
meta.timezone
string
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilitywrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
422

Something in the request isn't valid. fields says what, with the dashboard's wording.

validation_failed
  • validation_failed

    The given data was invalid.

422 response
{
  "error": {
    "code": "validation_failed",
    "message": "The given data was invalid.",
    "fields": {
      "name": [
        "The name field is required."
      ]
    }
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl 'https://api.bubbl.tech/platform/v1/reports/surveys' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/reports/surveys', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'GET',
    'https://api.bubbl.tech/platform/v1/reports/surveys',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bubbl.tech/platform/v1/reports/surveys', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);