BXP Protocol Specification
The normative definition of the BXP file format, agent schema, protocol stages, REST API, privacy framework, and conformance model.
- 1. Abstract
- 2. Terminology
- 3. Design Philosophy
- 4. Recommended Node Storage Layout (informative, non-normative)
- 5. The .bxp File Format
- 6. Agent Schema
- 6.8 Source Classification
- 7. Protocol Stages
- 8. REST API Specification
- 9. Security & Privacy Framework
- 10. Community Reporting Layer
- 11. Implementation Guide
- 12. Governance & Versioning
- 13. BXP-HRI (Experimental) — Health Risk Index
- 14. Compatibility Matrix
- 15. Conformance & Test Vectors
- Complete Agent Reference
- Geohash Reference
- Error Codes
- Glossary
- Origin & Authorship
- References
> Breathe Exposure Protocol — Complete Technical Reference
>
> | | |
> |---|---|
> | Status | Stable. The v2.0 wire format is frozen. |
> | Version | 2.0 |
> | Frozen in v2 | The 32-byte container framing, checksum placement, and agent ID registry. These will not change within major version 2. |
> | Still open in MINOR | Optional fields, endpoints, and agents may be added. Implementations must ignore-and-preserve what they do not recognise (§5.7). |
> | Breaking changes | Require a new major version, 18 months advance notice, and dual-version support (§12). |
> | License | Apache 2.0 |
> | Conformance | 17 golden vectors, §15 |
>
> BXP-HRI (§13) is experimental. It is not clinically or epidemiologically
> validated and must not be used for medical decisions.
---
1. Abstract
BXP (Breathe Exposure Protocol) is an open, universal file system
specification and data standard for the capture, storage, transmission,
and interpretation of atmospheric exposure data.
It defines the structural foundation upon which air quality applications,
governmental monitoring systems, research databases, health platforms,
and community reporting tools can interoperate — using a single,
standardized, open data layer.
BXP is a pure software protocol standard. Like HTTP, PDF, MP3, and SSL —
it requires no proprietary hardware, no centralized infrastructure, and
no licensing fees. It runs on any device, any platform, any geography,
at any scale.
BXP is to breath exposure data what HTTP is to the web.
1.1 The Problem
Air pollution causes 7 million premature deaths annually — more than
HIV, malaria, and tuberculosis combined (WHO, 2024). The tools to
measure, track, and respond to air pollution exist. The problem is
the data infrastructure does not.
Four critical failures define the current ecosystem:
| Failure | Description |
|---|---|
| Fragmentation | Every device, app, and agency uses incompatible formats |
| Proprietary lock-in | Closed ecosystems with expensive licensing |
| Geographic inequality | Monitoring concentrated in wealthy nations |
| No universal standard | No open protocol exists for air exposure data |
A sensor in Accra cannot speak to a hospital in Nairobi.
A citizen reading in Delhi cannot contribute to a government map.
A researcher in London cannot access ground-truth data from Lagos.
BXP eliminates this fragmentation permanently.
1.2 Scope
BXP v2.0 covers all outdoor and indoor atmospheric exposure data
including particulate matter, gaseous pollutants, volatile organic
compounds, biological agents, heavy metal particulates, and
environmental variables. Extension into waterborne and soil
contamination is planned for v3.0.
---
2. Terminology
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in RFC 2119.
| Term | Definition |
|---|---|
| BXP Volume | A complete BXP file system instance on any storage substrate |
| Agent | Any atmospheric substance or biological entity tracked by BXP |
| Reading | A single point-in-time measurement record |
| Aggregate | A computed summary of multiple readings over time or space |
| Geohash | A compact geographic coordinate encoding system |
| BXP-HRI (experimental) | BXP Health Risk Index — composite health risk score (0–100), not clinically validated |
| Container | A portable, self-verifying file bundling one or more readings |
| Device Token | Authentication credential issued to a data source |
| Quality Flag | A metadata tag describing data reliability |
---
3. Design Philosophy
BXP is built on six non-negotiable principles:
3.1 Universality
BXP MUST work for any data source, any platform, any geography,
and any scale — from a single phone to a planetary monitoring network.
3.2 Interoperability
Any BXP-compliant system MUST be able to read any BXP-compliant file
regardless of origin, device, or platform.
3.3 Openness
The standard is fully open. No licensing fees. No closed sections.
No gatekeepers. MIT and Apache 2.0 licensed. Forever free.
3.4 Accessibility
BXP MUST be implementable on low-resource devices including basic
smartphones, embedded systems, and offline environments.
3.5 Privacy-First
Individual exposure records are private by default. Cryptographic
controls operate at the file level. No surveillance assumptions
are permitted.
3.6 Extensibility
The standard MUST grow without breaking existing implementations.
All extensions use versioned namespaces. Backward compatibility
is maintained across all MINOR versions.
3.7 Conformance Model — what is normative
Earlier drafts of this specification left it ambiguous which parts an
independent implementation is required to reproduce byte-for-byte, and
which parts are merely one way a node might choose to organize its
own storage. That ambiguity is resolved here, explicitly, because it
determines what "BXP-compliant" actually means.
Normative (an implementation MUST get these exactly right to
interoperate; conformance test vectors exist for these — see §15):
- §5 The
.bxprecord — its JSON schema, its binary encoding, byte
layout, checksums, and the lossless JSON⇄binary conversion rule.
- §5.5 Verification (canonical serialization, SHA-256 payload hash).
- Versioning and compatibility rules (§3.6, §5.9, §12.2).
- The Agent Schema (§6) — agent IDs, units, canonical value ranges.
Informative / recommended (useful defaults a node or application
MAY follow, but which carry no interoperability obligation — two
compliant BXP implementations that disagree about these are both
still compliant):
- §4 the "BXP Volume" directory layout below. This describes one
reasonable way a node might index and cache records it has
collected — it is not a filesystem or database format that .bxp
itself must implement, and no .bxp file is required to reflect
this layout in any way.
- §8 the REST API's exact route names beyond the wire payloads they
carry.
- §11 example code.
Why this matters: a .bxp file is one self-contained record —
analogous to a .png or .mp4 file, not to a directory tree. A
sensor, an ESP32, a phone, and a BXP node all read and write the same
.bxp bytes. What any of them do with those bytes afterwards —
store them in a directory tree, a relational database, an S3 bucket,
or nothing at all — is an application-layer decision, not part of the
interoperability contract. Earlier text in this document (§4) blurred
that line by describing the directory tree in normative-sounding
language ("A BXP volume is a logical file system structure"); that
framing is corrected below.
---
4. Recommended Node Storage Layout (informative, non-normative)
This section describes one reasonable way a BXP node — a server,
gateway, or application that accumulates many .bxp records — MAY
organize them for its own indexing and retrieval. It is not part of
the wire format, it is not required for conformance, and no other
implementation needs to know or care whether a given node uses it.
A node MAY instead use a SQL database (as reference-server/ does),
a key-value store, flat files, or anything else, provided it can
still produce and accept valid .bxp records (§5) at its boundary.
It can be implemented on any physical storage: local disk, cloud
object store (S3, GCS), a relational database, or embedded flash.
The logical structure below is a naming convention, not a required
schema.
4.1 Root Structure
BXP:/
├── /meta/
├── /locations/
├── /agents/
├── /exposures/
├── /devices/
├── /alerts/
├── /community/
├── /research/
└── /system/
4.2 /meta — Volume Metadata
/meta/
├── volume.bxp — volume identity, version, owner, created
├── schema.bxp — schema version in use
├── index.bxp — master index of all records
├── checksums.bxp — Merkle tree integrity hashes
└── extensions/ — custom extension definitions
Every BXP volume MUST contain a valid /meta/volume.bxp file.
4.3 /locations — Geographic Hierarchy
/locations/
└── [continent]/
└── [country-iso]/
└── [region]/
└── [geohash-5]/ (~4.9km × 4.9km cell)
└── [geohash-7]/ (~153m × 153m cell)
├── current.bxp
├── history/
│ └── YYYY/
│ └── MM/
│ └── DD.bxp
├── events/
└── profile.bxp
4.4 /agents — Pollutant Definitions
/agents/
├── particulates/
│ ├── PM1.agent.bxp
│ ├── PM2_5.agent.bxp
│ └── PM10.agent.bxp
├── gases/
│ ├── CO.agent.bxp
│ ├── CO2.agent.bxp
│ ├── NO2.agent.bxp
│ ├── SO2.agent.bxp
│ ├── O3.agent.bxp
│ ├── H2S.agent.bxp
│ └── NH3.agent.bxp
├── vocs/
│ ├── TVOC.agent.bxp
│ ├── benzene.agent.bxp
│ ├── formaldehyde.agent.bxp
│ └── toluene.agent.bxp
├── biological/
│ ├── mold.agent.bxp
│ ├── pollen.agent.bxp
│ ├── bacteria.agent.bxp
│ └── virus.agent.bxp
├── heavy_metals/
│ ├── lead.agent.bxp
│ ├── mercury.agent.bxp
│ └── arsenic.agent.bxp
└── environmental/
├── temperature.agent.bxp
├── humidity.agent.bxp
├── pressure.agent.bxp
└── uv_index.agent.bxp
4.5 /exposures — Exposure Records
/exposures/
├── devices/
│ └── [device-uuid]/
│ ├── raw/ — immutable raw readings
│ └── processed/ — calibrated, validated readings
├── persons/ — encrypted by default
│ └── [sha256-of-person-id]/
│ ├── timeline.bxp
│ ├── risk_profile.bxp
│ └── health_events/
└── aggregates/
├── hourly/
├── daily/
├── monthly/
└── annual/
4.6 /devices — Device Registry
/devices/
└── [device-uuid]/
├── identity.bxp
├── calibration/
│ └── YYYY-MM-DD.cal.bxp
├── location_history/
└── health/
4.7 /community — Community Reports
/community/
├── reports/
│ └── [geohash-7]/
│ └── YYYY-MM-DD/
│ └── [report-uuid].bxp
└── events/
└── [event-uuid]/
├── metadata.bxp
└── attachments/
---
5. The .bxp File Format
5.1 Overview
The .bxp file format is BXP's native data format — a structured,
versioned, optionally compressed and encrypted container. Two
representations exist:
- Binary
.bxp— compact, efficient, designed for devices - JSON
.bxp.json— human-readable, designed for APIs
Both are semantically identical. Any BXP implementation MUST support
both and MUST be capable of lossless conversion between them.
5.2 Binary Header (32 bytes)
| Offset | Length | Field | Description |
|---|---|---|---|
| 0x00 | 4 bytes | Magic Number | 0x42585000 ("BXP\0") |
| 0x04 | 2 bytes | Major Version | Schema major version (uint16 big-endian) |
| 0x06 | 2 bytes | Minor Version | Schema minor version (uint16 big-endian) |
| 0x08 | 1 byte | File Type | 0x01=reading, 0x02=aggregate, 0x03=agent, 0x04=device, 0x05=alert, 0x06=meta |
| 0x09 | 1 byte | Flags | bit0=compressed, bit1=encrypted, bit2=signed, bit3=draft |
| 0x0A | 2 bytes | Reserved | Must be 0x0000 in v2.0 |
| 0x0C | 8 bytes | Timestamp | Unix epoch microseconds (int64 big-endian) |
| 0x14 | 4 bytes | Payload Length | Payload size in bytes (uint32 big-endian) |
| 0x18 | 4 bytes | Header Checksum | CRC32 of bytes 0x00–0x17 |
| 0x1C | 4 bytes | Payload Checksum | CRC32 of entire payload |
5.3 Reading Record Schema
{
"bxpVersion": "2.0",
"fileType": "reading",
"deviceUuid": "550e8400-e29b-41d4-a716-446655440000",
"geohash": "s1v0g",
"latitude": 5.5571,
"longitude": -0.1969,
"altitudeM": 61.0,
"timestampUs": 1710000000000000,
"durationS": 60,
"indoorOutdoor": "outdoor",
"agents": [
{
"agentId": "PM2_5",
"value": 47.3,
"unit": "ug/m3",
"uncertainty": 3.1,
"method": "optical",
"belowLod": false
},
{
"agentId": "CO",
"value": 1.2,
"unit": "ppm",
"uncertainty": 0.1,
"method": "electrochemical",
"belowLod": false
}
],
"context": {
"temperatureC": 28.4,
"humidityPct": 72.1,
"pressureHpa": 1012.3,
"windSpeedMs": 2.1,
"windDirDeg": 220
},
"quality": {
"flag": "VALIDATED",
"confidence": 0.94,
"qcMethod": "automated-v2",
"notes": ""
},
"signature": ""
}
5.5.1 Calibration & Correction (per-agent, OPTIONAL)
This is deliberately called out on its own because it's where a large,
well-documented, real-world failure mode lives: low-cost PM2.5 sensors
(the optical scattering sensors used in most Tier 1/2 hardware) read
high in humid conditions and need a correction against a colocated
reference instrument to be trustworthy — mixing corrected and
uncorrected values in one dataset without saying which is which is a
known source of bad air-quality decisions. BXP does not mandate any
particular correction algorithm, but it does mandate that if a value
has been corrected, that fact travels with the value:
{
"agentId": "PM2_5",
"value": 31.8,
"unit": "ug/m3",
"uncertainty": 4.2,
"method": "optical",
"belowLod": false,
"correction": {
"applied": true,
"rawValue": 47.3,
"model": "epa_pm25_humidity_v1",
"referenceDeviceUuid": "9c1e2b0a-....-....-....-............",
"correctedAt": 1710000012000000
}
}
- If
correctionis omitted, the value is exactly what the sensor
reported (correction.applied is implicitly false). This MUST be
the default assumption a reader makes about an agent entry with no
correction object.
- If
correction.appliedistrue,valueis the corrected value
and rawValue SHOULD be included so nothing is destroyed —
a downstream consumer that trusts a different correction model can
recover the original reading.
modelis a free-text identifier (not enumerated here on purpose;
correction science moves faster than protocol revisions) but SHOULD
be documented wherever the device or node publishes its methodology.
referenceDeviceUuid, when present, names the reference-grade
device (Tier 3, see below) this correction was derived from or
colocated against, giving an auditable link from a Tier 1/2 reading
back to the reference data that made it trustworthy.
- A writer MUST NOT set
quality.flagtoVALIDATEDfor a Tier 1/2
source unless either correction.applied is true or an equally
explicit qcMethod justifies it in quality.notes — an unvalidated
raw sensor value being labeled VALIDATED just because someone judged
it was "probably fine" is exactly the kind of quiet drift this field
exists to prevent.
5.4 Container Schema
A BXP Container is a portable, self-verifying file bundling one
or more readings. Derived from BXP v1.0 container specification.
{
"containerSchema": "bxp.container.v2",
"payload": {
"protocol": "Breathe Exposure Protocol",
"version": "2.0",
"owner": "user",
"generatedAt": "2026-03-04T08:00:00Z",
"readings": []
},
"payloadHash": "sha256:...",
"signature": "ed25519:...",
"verification": {
"method": "sha256+ed25519",
"status": "Verified"
}
}
5.5 Verification Process
Verification MUST follow this exact process:
1. Canonically serialize payload using sorted JSON keys
2. Compute SHA-256 hash of the UTF-8 encoded serialization
3. Compare computed hash to payloadHash
4. If hashes match: verification.status = "Verified"
5. If hashes do not match: verification.status = "Tampered"
6. If Ed25519 signature present: verify against device public key
5.6 Quality Flags
| Flag | Code | Description |
|---|---|---|
| VALIDATED | 0 | Passed all automated QC checks |
| UNVALIDATED | 1 | Raw data, no QC applied |
| SUSPECT | 2 | Failed one or more QC checks |
| INVALID | 3 | Known bad data — do not use |
5.7 Unknown and Future Fields
This was previously unspecified; it is resolved as follows so that
MINOR-version growth (§3.6) is actually safe in practice, not just in
principle:
- A conformant reader encountering a JSON payload key it does not
recognize MUST ignore that key and continue processing the rest of
the record. It MUST NOT reject the record solely because of an
unrecognized key.
- A conformant reader/writer that round-trips a record it does not
fully understand (e.g. a relay or federation node) SHOULD preserve
unrecognized top-level keys unchanged, so that newer fields survive
passing through older infrastructure. Fields inside agents[]
entries follow the same rule per-entry.
- New REQUIRED fields MUST NOT be introduced within a MAJOR version.
Only OPTIONAL fields may be added in a MINOR version (§12.2).
- A reader MUST NOT infer meaning from an unrecognized field; "ignore
and preserve" is the entire contract. Interpreting an unknown field
is only safe once it is documented in a released MINOR version.
5.8 Version Negotiation and Compatibility
The binary header carries Major and Minor version separately (§5.2)
specifically so this check can be done without parsing JSON:
- Major version mismatch (file's major ≠ implementation's
supported major): the reader MUST refuse to interpret the payload
as a normal record. It MAY still report the file's declared version
back to the caller (e.g. for a diagnostic message), but MUST NOT
guess at the payload's structure.
- Minor version higher than supported (same major, file's minor >
implementation's supported minor): the reader MUST still parse the
record, per §5.7 — newer optional fields it doesn't recognize are
ignored, not fatal.
- Minor version lower than supported: always valid; older minor
versions never remove fields, only add them.
- There is deliberately no PATCH component in the binary header.
PATCH-level changes to this specification (typo fixes, clarified
wording, tightened prose) never change wire bytes or parsing
behavior — if a change would alter what bytes are valid or how they
are interpreted, it is at minimum a MINOR change and must bump the
minor version field.
5.9 Extension Mechanism
Implementations that need to carry data this specification does not
yet define MUST do so under a single top-level "ext" object, keyed
by a short reverse-namespace string, e.g.:
"ext": {
"org.example.mycompany": { "calibrationBatch": "B-2026-04" }
}
This keeps experimental or vendor-specific data from colliding with
future officially-assigned field names, while remaining subject to
the same ignore-and-preserve rule as any other unrecognized field
(§5.7). Fields MUST NOT be added directly at the record's top level
outside of an RFC-accepted MINOR version (§12.3); use ext instead.
5.10 Encryption (flag bit1) — deliberately unspecified
Flag bit1 in the binary header is reserved to indicate an encrypted
payload, but this specification does not yet pin down a cipher suite
or key-exchange mechanism, and no BXP implementation should claim to
support it. Setting bit1 without a ratified encryption RFC is a
non-conformant file. sdk/python/bxp_binary.py reflects this
honestly: it raises rather than silently emitting a non-interoperable
"encrypted" file. Encrypting a whole .bxp file at rest using
external, off-the-shelf tooling (disk encryption, an encrypted
archive, etc.) remains a fine and fully conformant thing to do — it
just isn't this flag.
---
6. Agent Schema
6.1 Particulate Matter
| Agent ID | Name | Unit | WHO Annual | WHO 24h | Health Impact |
|---|---|---|---|---|---|
| PM1 | Particulate Matter <1μm | μg/m³ | — | — | Deep lung penetration, bloodstream entry |
| PM2_5 | Fine Particulate Matter <2.5μm | μg/m³ | 5 | 15 | Cardiovascular disease, lung cancer, stroke |
| PM10 | Coarse Particulate Matter <10μm | μg/m³ | 15 | 45 | Respiratory inflammation, asthma |
| BC | Black Carbon | μg/m³ | — | — | Climate forcing; linked to PM2.5 effects |
6.2 Gaseous Pollutants
| Agent ID | Name | Unit | WHO Limit | Primary Sources |
|---|---|---|---|---|
| CO | Carbon Monoxide | ppm | 4 mg/m³ (24h) | Combustion, generators, cooking fires |
| CO2 | Carbon Dioxide | ppm | 1000 (indoor) | Respiration, combustion |
| NO2 | Nitrogen Dioxide | ppb | 10 μg/m³ annual | Vehicle exhaust, power plants |
| SO2 | Sulphur Dioxide | ppb | 40 μg/m³ (24h) | Coal burning, industrial |
| O3 | Ground-level Ozone | ppb | 100 μg/m³ (8h) | Photochemical reaction |
| H2S | Hydrogen Sulphide | ppb | 7 ppb | Sewage, industrial waste |
| NH3 | Ammonia | ppm | 25 ppm | Agriculture, waste decomposition |
6.3 Volatile Organic Compounds
| Agent ID | Compound | Unit | Threshold | Classification |
|---|---|---|---|---|
| TVOC | Total VOC | ppb | >500 ppb | Aggregate |
| BENZ | Benzene | ppb | >1 ppb | Group 1 Carcinogen (IARC) |
| FORM | Formaldehyde | ppb | >8 ppb | Group 1 Carcinogen (IARC) |
| TOLU | Toluene | ppm | >50 ppm | Neurotoxin |
| XYLE | Xylene | ppm | >100 ppm | Neurotoxin |
| NAPH | Naphthalene | ppb | >9.4 ppb | Possible carcinogen |
6.4 Biological Agents
| Agent ID | Agent | Unit | Guideline |
|---|---|---|---|
| MOLD_S | Mold Spores | spores/m³ | >500 indoor concern |
| POLL_G | Grass Pollen | grains/m³ | >50 moderate season |
| POLL_T | Tree Pollen | grains/m³ | >100 high season |
| BACT_T | Total Bacteria | CFU/m³ | >500 indoor guideline |
| DUST_M | Dust Mite Allergen | ng/m³ | >2 ng/m³ |
6.5 Heavy Metals
| Agent ID | Element | Unit | WHO Guideline |
|---|---|---|---|
| PB | Lead | μg/m³ | 0.5 μg/m³ annual |
| HG | Mercury | μg/m³ | 1 μg/m³ (1-year) |
| AS | Arsenic | ng/m³ | 6.6 ng/m³ annual |
6.6 Environmental Variables
| Agent ID | Variable | Unit |
|---|---|---|
| TEMP | Temperature | °C |
| RH | Relative Humidity | % |
| PRESS | Atmospheric Pressure | hPa |
| UV | UV Index | index (0–11+) |
6.7 Derived Indices
| Index ID | Name | Basis | Scale |
|---|---|---|---|
| AQI_US | US Air Quality Index | PM2.5, PM10, CO, NO2, SO2, O3 | 0–500 |
| AQI_EU | European AQI | PM2.5, PM10, NO2, SO2, O3 | 1–5 bands |
| BXP_HRI_EXP | BXP Health Risk Index (experimental) | All available agents, weighted | 0–100 |
---
6.8 Source Classification
Every BXP reading MUST carry a source field classifying its provenance. This prevents imported/external data from being misrepresented as native BXP-certified measurements.
| Source Class | Code | Description | Trust Level |
|---|---|---|---|
| NATIVE | native | BXP-certified sensor, directly speaking BXP protocol | Highest — full QC chain |
| IMPORTED | imported | Converted from external API (OpenAQ, PurpleAir, AQICN, etc.) | Medium — depends on source QC |
| COMMUNITY | community | Low-cost / citizen sensor, no reference calibration | Low — UNVALIDATED by default |
| RESEARCH | research | Research-grade instrument, documented calibration | High — VALIDATED if documented |
| SIMULATED | simulated | Synthetic/test data, models, forecasts | None — for testing only |
Rules:
sourcefield is REQUIRED on all readings (top-level, not inagents[])sourceMUST be one of the five codes above- NATIVE readings MUST include
calibrationobject per agent (SPEC §5.5.1) or explicitqcMethod - IMPORTED readings MUST include
ext.sourcewith original API name (e.g.,"openaq","purpleair","aqicn") - COMMUNITY readings default to
quality.flag = "UNVALIDATED"unless QC evidence provided - SIMULATED readings MUST NOT be served on production
/nearbyor/latestendpoints
Example:
{
"source": "imported",
"ext": { "source": "openaq", "originalId": "location-8118" },
"quality": { "flag": "UNVALIDATED", "confidence": 0.5 }
}
---
7. Protocol Stages
Stage 1 — LOCATE
Every BXP record MUST be geographically contextualized.
Location Requirements:
| Requirement | Rule |
|---|---|
| Minimum precision | Geohash precision 5 (~4.9km cell) |
| Recommended precision | Geohash precision 7 (~153m cell) |
| High precision | Geohash precision 9 (~4.8m cell) |
| Coordinates | WGS84 decimal degrees where available |
| Indoor flag | MUST be set for all records |
| Altitude | SHOULD be included where elevation affects readings |
Location Acquisition Methods:
| Method | Code | Accuracy |
|---|---|---|
| GPS/GNSS | GPS | 3–10m |
| Network/Cell | NET | 50–500m |
| Manual entry | MAN | Variable |
| IP geolocation | IPG | City-level (flagged LOW_PRECISION) |
Stage 2 — DETECT
BXP accepts data from any source. No proprietary hardware required.
Data Source Tiers:
| Tier | Sources | Quality Flag |
|---|---|---|
| Tier 1 | Phone-native sensors, manual observation, existing apps | UNVALIDATED |
| Tier 2 | Consumer sensors, government open data feeds, satellites | UNVALIDATED → VALIDATED |
| Tier 3 | Reference instruments, certified monitoring stations | VALIDATED |
All tiers produce valid BXP data. Quality flags reflect reliability.
A network of 10,000 Tier 1 sources provides more spatial coverage
than 10 Tier 3 sources, even accounting for individual error.
This is not a hypothetical trade-off: as of 2026, funding for
government-operated reference-grade air monitoring networks has been
shrinking in real, documented ways (site closures, reduced sampling
frequency, discontinued public feeds), while low-cost sensor
deployments (PurpleAir-style optical sensors, community and
university networks across sub-Saharan Africa and elsewhere) have
become the fastest-growing source of coverage, if not of
individually reference-grade accuracy. BXP's job is not to pretend
Tier 1/2 data is as good as Tier 3 — it is to carry the difference
faithfully (§5.5.1) so an application built on BXP can make an honest
trade-off between coverage and precision, instead of being forced to
either discard low-cost data entirely or trust it uncritically.
Required Fields for a Valid Reading:
deviceUuid— REQUIREDgeohash— minimum precision 5 — REQUIREDtimestampUs— Unix epoch microseconds UTC — REQUIRED- At least one
agentsentry withvalue,unit,agentId— REQUIRED quality.flag— must be explicitly set — REQUIRED
Stage 3 — INTERPRET
Automated QC Rules (PM2.5 example):
| Check | Rule | Result |
|---|---|---|
| Range | 0 ≤ PM2.5 ≤ 1000 μg/m³ | Outside range → INVALID |
| Spike | Change >200 μg/m³ in <60s | → SUSPECT |
| Flatline | Identical value >30 min | → SUSPECT |
| Humidity | RH >75% | Apply Barkjohn correction |
| Cross-sensor | >300% difference from nearby source | → SUSPECT |
Unit Normalization:
All readings MUST be converted to BXP canonical units:
- Particulates: μg/m³ at standard conditions (25°C, 1 atm)
- Gases: ppb at standard conditions
- Temperature corrections MUST be applied before storage
Stage 4 — PROTECT
BXP Risk Level Framework (based on BXP-HRI experimental):
| Level | BXP-HRI (exp.) | AQI Equiv | Color | General Population | Sensitive Groups |
|---|---|---|---|---|---|
| CLEAN | 0–20 | 0–50 | Green | No restrictions | No restrictions |
| MODERATE | 21–40 | 51–100 | Yellow | Acceptable for most | Limit heavy exertion |
| ELEVATED | 41–60 | 101–150 | Orange | Reduce heavy outdoor exertion | Avoid outdoor exertion |
| HIGH | 61–75 | 151–200 | Red | N95 outdoors. Close windows. | Avoid outdoors. Air purifier. |
| VERY HIGH | 76–90 | 201–300 | Purple | Avoid outdoors. N95 mandatory. | Stay indoors. Seek medical help if symptomatic. |
| HAZARDOUS | 91–100 | 301–500 | Maroon | Emergency. Stay indoors. | Evacuate to cleaner air if possible. |
Stage 5 — REPORT
Community reports differ from device readings in that they include
qualitative human observations alongside quantitative data.
Report Components:
- Sensor readings (optional but recommended)
- Visual observations: smoke color, haze band, visibility
- Olfactory observations: odor type and intensity
- Symptom reports: correlated with location and time
- Event tags:
open_burning,traffic_jam,industrial_accident - Photo attachments with GPS EXIF metadata
Stage 6 — DISCOVER
A person's device does not need its own sensor to benefit from BXP.
If a Tier 1–3 source recorded a reading nearby, recently, a BXP node
SHOULD be able to surface it as the most relevant available
observation — not simply the nearest row in a database.
Relevance is a function of, at minimum:
| Factor | Effect |
|---|---|
| Distance from query point | Closer is more relevant, up to radiusM |
| Freshness | Newer is more relevant, up to maxAgeS |
| Quality flag | VALIDATED > UNVALIDATED > SUSPECT; INVALID excluded |
| Uncertainty | Lower uncertainty on the agent value is more relevant |
| Source tier | Tier 3 (reference-grade) may be weighted above Tier 1 |
No single factor should dominate to the point of returning a
technically-nearest but stale or low-quality reading over a
slightly-farther fresh, validated one. §8.2.1 defines the concrete
query surface for this; the ranking function itself is intentionally
not frozen into the wire protocol, since it is a quality-of-result
concern, not an interoperability concern — two nodes may legitimately
rank differently and both be BXP-compliant.
Stage 7 — FEDERATE
A single BXP node is useful. A network of independently operated BXP
nodes, each able to replicate from the others, is what makes "a
sensor in Accra" reachable from "a hospital in Nairobi" (§1.1).
At this stage, BXP defines only the minimum viable federation
primitive — a pull-based sync — deliberately leaving harder problems
for later RFCs rather than guessing at them now:
- Node identity & discovery:
POST /nodes/announcelets a node
register itself with a peer (§8.2); there is no discovery protocol
beyond direct announcement yet (e.g. no DHT, no well-known registry).
- Replication:
GET /sync?since=<cursor>(§8.2.2) lets a node pull
everything newer than its last-seen watermark from a peer. This is
enough to build a full mesh by having every node periodically sync
from every other node it knows about (from GET /nodes).
- Provenance: every replicated reading carries its originating
nodeId, so a record's chain of custody survives being copied
between nodes.
- Deliberately NOT yet specified — trust/reputation between
nodes, deduplication policy when the same physical reading arrives
via two paths, conflict resolution for edited/deleted records,
partial-connectivity/offline-node backfill, and query routing
across a federation (asking node A to transparently include node
B's data in a /nearby response). These are real problems; they
are left open rather than answered with an untested design, because
a wrong answer here is expensive to walk back once nodes depend on
it. A future RFC (§12.3) should address them once real multi-node
deployments surface actual failure modes to design against.
---
8. REST API Specification
8.1 Base URL
https://[host]/bxp/v2/
8.2 Endpoints
Route names are informative (§3.7) — the payload shapes they carry
are what implementations must agree on. The table below has been
reconciled against reference-server/, the actual reference
implementation, which is the one that previously drifted from this
document. Columns marked Status: planned describe endpoints this
specification recommends but which the reference server does not yet
implement; treat those as a roadmap, not a claim of what exists today.
| Method | Endpoint | Description | Auth | Status |
|---|---|---|---|---|
| GET | /bxp/v2/health | Liveness/readiness check | No | Implemented |
| GET | /bxp/v2/readings | List/query readings (geohash, time range, agent, quality) | No | Implemented |
| POST | /bxp/v2/readings | Submit one or more readings (JSON or binary .bxp body) | Device Token | Implemented |
| GET | /bxp/v2/readings/{readingId} | Get reading by ID (?format=binary for .bxp) | No | Implemented |
| DELETE | /bxp/v2/readings/{readingId} | Delete a reading, with deletion proof | User/Device Token | Implemented |
| GET | /bxp/v2/readings/{readingId}/verify | Re-run §5.5 verification, return status | No | Implemented |
| GET | /bxp/v2/locations/{geohash}/latest | Most recent reading at a location | No | Implemented |
| GET | /bxp/v2/locations/{geohash}/history | Historical readings at a location | No | Implemented |
| GET | /bxp/v2/locations/{geohash}/aggregate | Statistical summary for a location | No | Implemented |
| GET | /bxp/v2/nearby | New (§7 Stage 6): most relevant observation(s) near a lat/lon, ranked by distance, freshness and quality — see §8.2.1 | No | Implemented |
| GET | /bxp/v2/search | Search by bounding box, time, agent | No | Implemented |
| POST | /bxp/v2/community/reports | Submit community report | User Token | Implemented |
| GET | /bxp/v2/community/reports | List community reports | No | Implemented |
| POST | /bxp/v2/devices/register | Register a new device or source | API Key | Implemented |
| GET | /bxp/v2/devices/{uuid} | Get device metadata | Device Token | Implemented |
| GET | /bxp/v2/nodes | List known federated nodes | No | Implemented |
| POST | /bxp/v2/nodes/announce | Announce this node to a peer | No | Implemented |
| GET | /bxp/v2/sync | New (§7 Stage 7): pull changes (readings and deletion tombstones) after a cursor, for federation replication — see §8.2.2 | Node Token | Implemented |
| GET | /bxp/v2/agents | List all supported agents | No | Planned |
| GET | /bxp/v2/agents/{agentId} | Full agent specification | No | Planned |
| POST | /bxp/v2/devices/{uuid}/calibration | Submit calibration record | Device Token | Planned |
| GET | /bxp/v2/alerts | Active alerts for a location | No | Planned |
| DELETE | /bxp/v2/persons/{hash} | Permanently delete personal records | User Token | Planned |
#### 8.2.1 GET /bxp/v2/nearby — relevance-ranked lookup
This is the endpoint behind the "walking with no sensor of your own"
use case (§7 Stage 6): the caller wants the single best available
observation near them, not an arbitrary row from an exact grid cell.
| Parameter | Type | Default | Description |
|---|---|---|---|
lat, lon | float | required | WGS84 query point |
radiusM | integer | 2000 | Search radius in meters |
maxAgeS | integer | 3600 | Discard readings older than this |
agent | string | any | Restrict to one agent ID (e.g. PM2_5) |
minQuality | enum | UNVALIDATED | Minimum acceptable quality flag |
limit | integer | 1 | Number of ranked candidates to return |
Candidates are found via geohash-prefix expansion (the query point's
geohash-5 cell and its 8 neighbors, which always fully covers a
radius up to ~4.9 km — see Appendix B), filtered to radiusM using
true great-circle distance, and ranked by a relevance score that
combines recency, distance, and quality rather than any single one of
these alone. A field measurement 3 minutes old and 400m away should
usually outrank one 55 minutes old and 50m away. The exact scoring
weights are an implementation detail (see
reference-server/database.py::get_nearby_readings); the contract is
the ranking behavior, not a fixed formula, since better ranking
heuristics are expected to evolve without breaking the API shape.
#### 8.2.2 GET /bxp/v2/sync — federation pull
Query parameters: since (integer cursor, default 0 = from the beginning),
limit (default 500, max 2000). The response carries the changes after that
cursor, oldest first, and a nextCursor to resume from.
- The cursor is an opaque, node-local ingest sequence, not an observation
timestamp. A timestamp cursor is unsound: a device can report any timestamp,
so one far-future reading would stall replication forever, and a reading that
arrives late from an offline device (older timestamp) would be skipped. A
caller MUST treat the cursor as opaque and only echo back nextCursor.
- Each reading carries its originating
nodeId(provenance, §7 Stage 6). - Deletions replicate. A deleted reading is delivered as a tombstone
{"readingId": "...", "deleted": true, "deletionProof": "sha256:..."}
containing no observation data. A replica MUST erase its copy on receipt
(§9.1: deletion is irreversible).
- A reading whose
readingIdalready exists is never overwritten; replicas
dedupe by readingId.
This is the minimum a second node needs in order to replicate. What is
deliberately not yet specified (trust, conflict resolution, cross-peer dedup
policy) is listed in §7 Stage 7.
---
9. Security & Privacy Framework
9.1 Privacy Architecture
BXP treats individual exposure data as sensitive personal health
information. The following rules are NON-NEGOTIABLE in any
BXP-compliant implementation:
- Personal exposure records are private by default
- Person identifiers are NEVER stored in plain form
- Only SHA-256 hashes of user-controlled identifiers are stored
- Location precision for personal records defaults to Geohash 5
- Community aggregates are k-anonymized before publication (minimum k=5)
- Users can permanently delete all personal records via single API call
- Deletion is cryptographically verifiable and irreversible
9.2 Encryption Standards
| Data Type | Encryption | Key Derivation |
|---|---|---|
| Personal records at rest | AES-256-GCM | PBKDF2 from user credentials |
| Data in transit | TLS 1.3 minimum | — |
| Device readings (optional signing) | Ed25519 | Device key pair at registration |
| Volume integrity | SHA-256 Merkle tree | — |
BXP servers MUST NOT accept connections below TLS 1.2.
TLS 1.3 is REQUIRED for all personal data endpoints.
9.3 Data Integrity Model
BXP uses a four-layer integrity model:
Layer 1 — File Level
Every .bxp file includes CRC32 checksums of both header
and payload. Corruption is detectable on any read.
Layer 2 — Record Level
Optional Ed25519 cryptographic signature per reading,
verifiable against the device's registered public key.
Signed readings cannot be forged or altered without detection.
Layer 3 — Volume Level
/meta/checksums.bxp maintains a Merkle tree of all file
checksums. Enables efficient tamper detection across an
entire volume without reading every file.
Layer 4 — Audit Log
All write operations are logged in /system/audit.log
with timestamp, source UUID, operation type, and record hash.
Audit logs are append-only and cryptographically chained.
9.4 Regulatory Compliance
BXP is designed for compliance with:
| Regulation | Region | Key BXP Feature |
|---|---|---|
| GDPR | European Union | Right to erasure, data portability, purpose limitation |
| CCPA | California, USA | Right to access, right to delete, opt-out of sale |
| POPIA | South Africa | Data minimization, lawful processing |
| PDPA | Multiple Asian nations | Consent-based collection, breach notification |
| HIPAA | USA (health data) | Encryption at rest and in transit, audit logs |
---
10. Community Reporting Layer
10.1 Overview
Community reports combine human observation with structured data.
They recognize that a person who can see smoke, smell chemicals,
or feel eye irritation is a valid sensor — and that their
observations, aggregated across thousands of people, produce
intelligence that no hardware network can replicate.
10.2 Community Report Schema
{
"reportType": "community",
"reporterHash": "sha256:a3f9...",
"geohash": "s1v0g",
"latitude": 5.5571,
"longitude": -0.1969,
"timestampUs": 1710000000000000,
"observations": {
"visibleSmoke": true,
"smokeColor": "black",
"hazeBand": true,
"visibilityKm": 2.1,
"odorPresent": true,
"odorType": "burning_rubber",
"odorIntensity": 3
},
"symptoms": {
"eyeIrritation": true,
"coughing": true,
"headache": false,
"breathingDifficulty": false,
"skinIrritation": false
},
"eventTags": [
"open_burning",
"traffic_congestion"
],
"sensorReadings": [],
"photoAttachments": [
{
"hash": "sha256:b7c2...",
"mimeType": "image/jpeg",
"sizeBytes": 204800,
"gpsLat": 5.5571,
"gpsLon": -0.1969
}
],
"freeText": "Large fire visible at industrial site 200m north-west",
"confidence": 0.8,
"bxpVersion": "2.0"
}
10.3 Valid Event Tags
| Tag | Description |
|---|---|
open_burning | Open waste or biomass burning |
traffic_congestion | Heavy stationary traffic |
industrial_accident | Industrial facility incident |
dust_storm | Windblown dust event |
harmattan | Harmattan dust season (West Africa) |
wildfire | Wildfire smoke |
construction | Active construction site |
generator_exhaust | Generator operation nearby |
cooking_smoke | Charcoal or biomass cooking |
chemical_spill | Chemical release event |
sewage | Sewage exposure event |
pesticide_spray | Agricultural or urban spraying |
10.4 Community QC Pipeline
Community reports pass through five automated quality checks:
Check 1 — Geospatial Clustering
Reports within 500m and 30 minutes of each other are clustered.
Clustered events receive confidence boosts proportional to
the number of independent reporters.
Check 2 — Cross-Validation
Reports overlapping in space-time with sensor readings are
cross-validated. Consistency increases confidence of both
the report and the sensor reading.
Check 3 — Outlier Detection
Reports inconsistent with surrounding data are flagged SUSPECT
and queued for manual review before inclusion in aggregates.
Check 4 — Reporter Reliability Scoring
Over time, reporters whose observations consistently align with
verified data receive higher base confidence weights.
New reporters start at confidence 0.5. Maximum is 1.0.
Check 5 — Abuse Detection
Automated detection of repeated identical submissions,
geographically impossible submissions, timestamp manipulation,
and bot-pattern behavior. Flagged accounts are suspended
pending review.
---
11. Implementation Guide
11.1 Implementing a BXP Data Source
Any application, device, or system that produces BXP-formatted
data is a BXP data source. No hardware is required.
Minimum Viable Implementation — 6 Steps:
Step 1 — Generate UUID
Generate a UUID v4 for your source. This UUID is permanent.
import uuid
device_uuid = str(uuid.uuid4())
# Example: "550e8400-e29b-41d4-a716-446655440000"
Step 2 — Register with a BXP Volume
import requests
registration = {
"deviceUuid": device_uuid,
"sourceType": "phone_app",
"capabilities": ["PM2_5", "TEMP", "RH"],
"accuracyClass": "tier1",
"bxpVersion": "2.0"
}
response = requests.post(
"https://[bxp-server]/bxp/v2/devices/register",
json=registration,
headers={"Authorization": "Bearer [api-key]"}
)
device_token = response.json()["data"]["deviceToken"]
Step 3 — Build a Reading Record
from datetime import datetime, timezone
import time
reading = {
"bxpVersion": "2.0",
"fileType": "reading",
"deviceUuid": device_uuid,
"geohash": "s1v0g",
"latitude": 5.5571,
"longitude": -0.1969,
"timestampUs": int(time.time() * 1_000_000),
"durationS": 60,
"indoorOutdoor": "outdoor",
"agents": [
{
"agentId": "PM2_5",
"value": 47.3,
"unit": "ug/m3",
"uncertainty": 3.1,
"method": "optical",
"belowLod": False
}
],
"context": {
"temperatureC": 28.4,
"humidityPct": 72.1,
"pressureHpa": 1012.3
},
"quality": {
"flag": "UNVALIDATED",
"confidence": 0.7
}
}
Step 4 — Compute and Attach Hash
import json
import hashlib
payload_str = json.dumps(reading, sort_keys=True)
payload_hash = hashlib.sha256(
payload_str.encode("utf-8")
).hexdigest()
container = {
"containerSchema": "bxp.container.v2",
"payload": reading,
"payloadHash": f"sha256:{payload_hash}",
"verification": {
"method": "sha256",
"status": "Unverified"
}
}
Step 5 — Submit
response = requests.post(
"https://[bxp-server]/bxp/v2/readings",
json=container,
headers={"Authorization": f"Bearer {device_token}"}
)
Step 6 — Handle Offline / Buffer Locally
import json
import os
from pathlib import Path
BUFFER_PATH = Path("bxp_buffer/")
BUFFER_PATH.mkdir(exist_ok=True)
def submit_with_fallback(container, token):
try:
response = requests.post(
"https://[bxp-server]/bxp/v2/readings",
json=container,
headers={"Authorization": f"Bearer {token}"},
timeout=10
)
response.raise_for_status()
return True
except Exception:
# Buffer locally — file named by timestamp
ts = container["payload"]["timestampUs"]
buffer_file = BUFFER_PATH / f"{ts}.bxp.json"
with open(buffer_file, "w") as f:
json.dump(container, f)
return False
11.2 Implementing a BXP Application
Any application reading or displaying BXP data MUST:
- Display quality flags clearly — never present SUSPECT or
INVALID data as reliable without explicit labeling
- Use BXP canonical units with clear unit labels on all displays
- Implement the BXP risk level framework (Section 7, Stage 4)
- Use the correct BXP-HRI (experimental) color scheme for risk visualization
- Never cache personal exposure data beyond the immediate session
- Respect user deletion requests immediately and completely
11.3 Reference Implementations
| Implementation | Language | Repository |
|---|---|---|
| bxp-server | Python 3.11+ | github.com/bxpprotocol/bxp-server |
| bxp-server-node | Node.js 20+ | github.com/bxpprotocol/bxp-server-node |
| bxp-sdk-python | Python 3.11+ | github.com/bxpprotocol/bxp-sdk-python |
| bxp-sdk-js | JavaScript/TypeScript | github.com/bxpprotocol/bxp-sdk-js |
| bxp-sdk-arduino | C/C++ Arduino | github.com/bxpprotocol/bxp-sdk-arduino |
| bxp-sdk-esp32 | C/C++ ESP-IDF | github.com/bxpprotocol/bxp-sdk-esp32 |
| bxp-mobile | React Native | github.com/bxpprotocol/bxp-mobile |
---
12. Governance & Versioning
12.1 The BXP Foundation
BXP is governed by the BXP Foundation — an independent,
non-profit open standards body. Its mandate is to maintain,
evolve, and promote the BXP specification in the public
interest with no commercial bias and no single controlling entity.
Structure:
| Body | Role |
|---|---|
| Technical Steering Committee | 7 elected members. Responsible for all specification changes and version releases |
| Working Groups | Domain-specific: hardware, software, privacy, health, community |
| Advisory Board | WHO, national environmental agencies, manufacturers, academic institutions, civil society |
| Open Community | Any individual or organization may participate and propose changes |
12.2 Versioning Policy
BXP uses semantic versioning — MAJOR.MINOR.PATCH:
| Change Type | Version Impact | Compatibility |
|---|---|---|
| Bug fixes, clarifications | PATCH | Full backward and forward compatibility |
| New optional fields | MINOR | Backward compatible. Existing implementations do not break. |
| Breaking changes | MAJOR | 18 months advance notice required. Dual-version support during transition. |
12.3 RFC Process
All specification changes follow the BXP RFC process:
1. Any person submits RFC proposal via GitHub
2. Relevant Working Group reviews over 30-day public comment period
3. Technical Steering Committee votes: accept, reject, or return for revision
4. Accepted RFCs incorporated into next appropriate version release
---
13. BXP-HRI (Experimental) — Health Risk Index
13.1 Overview
BXP-HRI (experimental) is BXP's native composite health risk score on a 0–100
scale. Unlike single-pollutant indices such as AQI, BXP-HRI
incorporates all available agents with WHO-derived weighting,
exposure duration, and population vulnerability modifiers.
⚠️ Not clinically or epidemiologically validated. Do not use for medical decisions.
13.2 Agent Weights
| Agent | Weight | Basis |
|---|---|---|
| PM2.5 | 0.35 | Highest global DALY burden (WHO 2021) |
| PM10 | 0.15 | Significant respiratory burden |
| NO2 | 0.15 | High urban prevalence, lung inflammation |
| O3 | 0.12 | Strong respiratory effects, summer peaks |
| CO | 0.10 | Acute toxicity, high developing-world burden |
| SO2 | 0.05 | Regional industrial variation |
| TVOC | 0.04 | Indoor carcinogen concern |
| Biological | 0.04 | Contextual, high in humid environments |
13.3 Calculation Formula
Step 1 — Normalize each agent to 0–1 risk scale:
agent_risk(i) = min(1.0, value(i) / WHO_threshold(i))
Step 2 — Compute weighted sum:
raw_HRI = Σ ( agent_risk(i) × weight(i) )
Step 3 — Apply duration and vulnerability modifiers:
bxp_hri_experimental = min(100, raw_HRI × 100 × duration_factor
× vulnerability_factor)
Duration factors:
| Averaging Period | Factor |
|---|---|
| 1-hour average | 1.0 |
| 8-hour average | 1.2 |
| 24-hour average | 1.5 |
Vulnerability factors:
| Population | Factor |
|---|---|
| General population | 1.0 |
| Sensitive groups (children, elderly, respiratory conditions) | 1.3 |
13.4 Python Reference Implementation
WHO_THRESHOLDS = {
"PM2_5": 15.0,
"PM10": 45.0,
"NO2": 25.0,
"O3": 100.0,
"CO": 4.0,
"SO2": 40.0,
"TVOC": 500.0,
}
WEIGHTS = {
"PM2_5": 0.35,
"PM10": 0.15,
"NO2": 0.15,
"O3": 0.12,
"CO": 0.10,
"SO2": 0.05,
"TVOC": 0.04,
}
DURATION_FACTORS = {
"1h": 1.0,
"8h": 1.2,
"24h": 1.5,
}
VULNERABILITY_FACTORS = {
"general": 1.0,
"sensitive": 1.3,
}
def calculate_bxp_hri_experimental(agents, duration="1h", population="general"):
raw_hri = 0.0
for agent_id, value in agents.items():
if agent_id in WHO_THRESHOLDS and agent_id in WEIGHTS:
risk = min(1.0, value / WHO_THRESHOLDS[agent_id])
raw_hri += risk * WEIGHTS[agent_id]
duration_factor = DURATION_FACTORS.get(duration, 1.0)
vulnerability_factor = VULNERABILITY_FACTORS.get(population, 1.0)
bxp_hri_exp = min(100.0, raw_hri * 100 * duration_factor
* vulnerability_factor)
return round(bxp_hri_exp, 2)
# Example usage
agents = {
"PM2_5": 47.3,
"NO2": 38.0,
"CO": 1.2,
}
hri = calculate_bxp_hri_experimental(agents, duration="1h", population="general")
print(f"BXP-HRI (experimental): {hri}")
# Output: BXP-HRI (experimental): 34.21 → MODERATE
---
14. Compatibility Matrix
| Standard | Organization | BXP Compatibility |
|---|---|---|
| AQI | US EPA | BXP-HRI (experimental) maps directly. AQI_US is a supported derived field. |
| WHO Air Quality Guidelines 2021 | World Health Organization | All BXP thresholds align with WHO 2021 guidelines. |
| HL7 FHIR R4 | HL7 International | BXP exposure records map to FHIR Observation resources. |
| OGC SensorThings API | Open Geospatial Consortium | BXP implements a compatible observation model. |
| OpenAQ | OpenAQ | BXP can ingest and re-export OpenAQ data in standard format. |
| IEC 62484 | International Electrotechnical Commission | BXP binary format compatible with IEC sensor data standard. |
| Schema.org | W3C Community Group | BXP JSON uses Schema.org vocabulary where applicable. |
| GDPR | European Union | Privacy framework designed for full compliance. |
---
15. Conformance & Test Vectors
An implementation is BXP-conformant for the native format (§3.7) if it
produces and accepts byte-identical .bxp files for the same logical
record as the reference vectors in /conformance/vectors/.
15.1 What the vector suite covers
- Valid vectors: a fixed set of records (minimal reading, full
reading with all optional fields, aggregate, device, each file
type, each flag combination) encoded once by the Python reference
encoder and checked into the repository as golden .bxp files. Any
implementation's decoder MUST reproduce the same record from these
bytes. For uncompressed vectors, any implementation's encoder,
given the same input record, MUST also reproduce the exact same
bytes (encoding is fully deterministic there — sorted JSON keys,
fixed separators, no encode-time-generated values). For
compressed vectors, only the decoded record is required to
match exactly; the compressed byte stream itself is not required to
be bit-identical across independent gzip implementations (DEFLATE
does not guarantee identical output across libraries even for
identical input and mtime), so conformance there is defined as
round-trip correctness, not byte-for-byte re-encoding.
- Malformed vectors: bad magic number, truncated header, truncated
payload, corrupted header checksum, corrupted payload checksum, and
an unsupported major version. Every conformant decoder MUST reject
each of these with an error (not a crash, not a silently-wrong
parse) when run with verification enabled.
manifest.jsondescribes every vector: its filename, whether it
is expected to decode successfully, and if so the expected record
and header fields; if not, which check is expected to fail.
15.2 Running the suite
Each implementation ships a small runner that reads manifest.json
and checks its own encoder/decoder against it:
python3 conformance/verify_python.py
node conformance/verify_typescript.mjs
./conformance/c/bxp_conformance # built from embedded/c/
All three currently pass against the same vector files — this is the
concrete evidence that the Python, TypeScript, and embedded-C
implementations agree byte-for-byte on the native format, independent
of the HTTP server or any single SDK's internal representation.
15.3 Adding a vector
New edge cases (an additional flag combination, a boundary timestamp,
a newly-discovered malformed-input class) should be added as a new
file under conformance/vectors/ plus a corresponding entry in
manifest.json, generated via conformance/generate_vectors.py so
every vector's provenance (which encoder, which inputs) stays
reproducible.
---
Appendix A — Complete Agent Reference
| Agent ID | Full Name | Category | Unit | WHO Limit |
|---|---|---|---|---|
| PM1 | Particulate Matter <1μm | Particulates | μg/m³ | — |
| PM2_5 | Particulate Matter <2.5μm | Particulates | μg/m³ | 5 annual |
| PM10 | Particulate Matter <10μm | Particulates | μg/m³ | 15 annual |
| BC | Black Carbon | Particulates | μg/m³ | — |
| CO | Carbon Monoxide | Gas | ppm | 4 mg/m³ 24h |
| CO2 | Carbon Dioxide | Gas | ppm | 1000 indoor |
| NO2 | Nitrogen Dioxide | Gas | ppb | 10 μg/m³ annual |
| NO | Nitric Oxide | Gas | ppb | — |
| SO2 | Sulphur Dioxide | Gas | ppb | 40 μg/m³ 24h |
| O3 | Ground-level Ozone | Gas | ppb | 100 μg/m³ 8h |
| H2S | Hydrogen Sulphide | Gas | ppb | 7 ppb |
| NH3 | Ammonia | Gas | ppm | 25 ppm |
| TVOC | Total VOC | VOC | ppb | 500 ppb |
| BENZ | Benzene | VOC | ppb | No safe level |
| FORM | Formaldehyde | VOC | ppb | 8 ppb |
| TOLU | Toluene | VOC | ppm | 50 ppm |
| XYLE | Xylene | VOC | ppm | 100 ppm |
| NAPH | Naphthalene | VOC | ppb | 9.4 ppb |
| MOLD_S | Mold Spores | Biological | spores/m³ | 500 indoor |
| POLL_G | Grass Pollen | Biological | grains/m³ | 50 moderate |
| POLL_T | Tree Pollen | Biological | grains/m³ | 100 high |
| BACT_T | Total Airborne Bacteria | Biological | CFU/m³ | 500 indoor |
| DUST_M | Dust Mite Allergen | Biological | ng/m³ | 2 ng/m³ |
| PB | Lead | Heavy Metal | μg/m³ | 0.5 annual |
| HG | Mercury | Heavy Metal | μg/m³ | 1 annual |
| AS | Arsenic | Heavy Metal | ng/m³ | 6.6 annual |
| TEMP | Temperature | Environmental | °C | — |
| RH | Relative Humidity | Environmental | % | — |
| PRESS | Atmospheric Pressure | Environmental | hPa | — |
| UV | UV Index | Environmental | index | — |
| AQI_US | US Air Quality Index | Derived | 0–500 | — |
| BXP_HRI_EXP | BXP Health Risk Index (experimental) | Derived | 0–100 | — |
---
Appendix B — Geohash Reference
| Precision | Characters | Cell Width | Cell Height | BXP Use |
|---|---|---|---|---|
| 1 | 1 | ~5,000 km | ~5,000 km | Continental aggregates only |
| 2 | 2 | ~1,250 km | ~625 km | Country aggregates |
| 3 | 3 | ~156 km | ~156 km | Regional aggregates |
| 4 | 4 | ~39 km | ~20 km | City aggregates |
| 5 | 5 | ~4.9 km | ~4.9 km | Minimum valid BXP reading |
| 6 | 6 | ~1.2 km | ~0.61 km | Neighborhood level |
| 7 | 7 | ~153 m | ~153 m | Recommended for fixed sources |
| 8 | 8 | ~38 m | ~19 m | Street level |
| 9 | 9 | ~4.8 m | ~4.8 m | BXP-HIGHRES personal sensors |
---
Appendix C — Error Codes
| Code | HTTP Status | Meaning |
|---|---|---|
| BXP_4001 | 400 | Geohash precision below minimum (5) |
| BXP_4002 | 400 | Missing required field |
| BXP_4003 | 400 | Invalid agent ID |
| BXP_4004 | 400 | Unit not recognized for agent |
| BXP_4005 | 400 | Timestamp outside acceptable range |
| BXP_4006 | 400 | Payload hash mismatch — container tampered |
| BXP_4007 | 400 | Schema version not supported |
| BXP_4010 | 401 | Missing or invalid authentication token |
| BXP_4011 | 401 | Device token revoked |
| BXP_4030 | 403 | Insufficient permissions for operation |
| BXP_4040 | 404 | Reading or resource not found |
| BXP_4290 | 429 | Rate limit exceeded |
| BXP_5000 | 500 | Internal server error |
| BXP_5030 | 503 | BXP volume temporarily unavailable |
---
Appendix D — Glossary
| Term | Definition |
|---|---|
| Agent | Any atmospheric substance or biological entity BXP can track |
| BXP Volume | A complete BXP file system instance on any storage substrate |
| Container | A portable self-verifying file bundling one or more readings |
| Geohash | A compact geographic coordinate encoding used for spatial indexing |
| BXP_HRI | BXP Health Risk Index — composite health risk score 0–100 |
| Reading | A single point-in-time measurement record from one source |
| Aggregate | A computed summary of multiple readings over time or space |
| Device Token | Authentication credential for a data source writing to BXP |
| Community Report | A human-submitted observation record |
| Calibration Record | Links device readings to a reference standard at a point in time |
| Quality Flag | Metadata tag describing data reliability: VALIDATED through INVALID |
| k-anonymization | Privacy technique — no aggregate published with fewer than k sources |
| Tier 1/2/3 | BXP source capability tiers — Tier 1 phone/manual, Tier 3 reference |
| DALY | Disability-Adjusted Life Year — WHO measure of disease burden |
| Geohash-7 | ~153m × 153m geographic cell — BXP recommended precision |
| Prior Art | Publicly documented evidence of an invention before any patent claim |
---
Origin & Authorship
BXP was conceived and first implemented by Elvarin on
February 15, 2026. The original v1 specification established
the foundational concepts of user-owned data, offline-first
architecture, portable containers, and SHA-256 verification.
This document is the official BXP v2.0 Technical Specification
— a direct continuation of that original work.
---
References
Simcoe, T. (2012). Standard setting committees: Consensus
governance for shared technology platforms.
American Economic Review, 102(1), 305-336.
World Health Organization (2021). WHO Global Air Quality
Guidelines. Geneva: World Health Organization.
Copyright 2026 Elvarin — Licensed under Apache 2.0
The air is public. The data should be too.