5.1. Integration Best Practices¶
5.1.1. Use supported interfaces¶
Use the documented native REST API for new integrations.
BzAPI remains available as a compatibility layer, but it is deprecated.
Existing BzAPI integrations should migrate to the native REST API. If immediate
migration is not possible, use BMO’s built-in /bzapi/ compatibility
endpoint prefix instead of the retired standalone BzAPI service. The
compatibility layer performs additional request and response translation.
Do not rely on scraped HTML, bug lists exported as CSV or XML, or undocumented endpoints when your integration requires a stable interface. Use documented REST API methods that are not marked experimental. See the API overview for the other interfaces that Bugzilla provides.
5.1.2. Use a dedicated bot account¶
Do not reuse a person’s account for automation. Human accounts may acquire privileges that the integration does not need. Request a dedicated bot account by filing an Administration bug. Grant the account only the privileges required by the integration.
Authenticate with an API key in the X-BUGZILLA-API-KEY request header.
Do not put API keys in URLs, where they can be captured in logs and browser
history. See REST API authentication for details.
5.1.3. Poll responsibly¶
Following the original BMO integration policy, do not poll BMO more frequently than once every five minutes. If an integration needs lower-latency updates, use the Webhooks API. Contact the BMO team in the BMO Matrix channel to discuss requirements that the documented webhooks do not meet.
Authenticate polling and batch-read requests. BMO applies per-IP rate limits to
anonymous reads. The request that reaches a limit can return a JSON HTTP 400
rate-limit error, while subsequent requests from the blocked IP can return an
HTML HTTP 429 response. When either response occurs, retry with exponential
backoff and jitter. BMO does not currently send a Retry-After header. Apply
the same backoff to transient 5xx responses.
Poll incrementally instead of repeating a full search. The
last_change_time parameter to Search Bugs returns bugs modified
at or after the supplied timestamp. Bug searches may use a read replica, while
GET /rest/time reads the primary database. Because BMO does not guarantee a
maximum replication lag, an integration that requires a guaranteed polling
window should confirm the current operational guidance with the BMO team.
A polling cycle should:
obtain BMO’s current
db_timefrom GET /rest/time before searching;search from at least five minutes before the previous successful cycle’s recorded time to provide headroom for replica lag and one-second timestamp precision;
pass
order=bug_idand choose an explicit page size below BMO’s current 10,000-result search cap, such aslimit=1000. BMO silently lowers limits above the cap, so never use a larger requested value as the termination threshold. Page withlimitandoffsetuntil a page contains fewer bugs than the chosen page size. The response does not indicate when more results are available. Do not uselimit=0for paging; it discards the suppliedoffsetand the search remains capped;collect the bug IDs from every page, then fetch and process every unique bug before saving the new
db_time; anddiscard the de-duplication set after each cycle. If a bug appears in a later cycle, fetch it again even when its
last_change_timematches the value previously processed, because multiple changes can occur within the API’s one-second timestamp precision.
5.1.4. Minimize requests and responses¶
Request only the fields the integration uses by setting
include_fields. This reduces response size and
server work. For polling searches, use
include_fields=id,last_change_time and fetch the full bugs after all pages
have been collected.
Combine requests when possible. For example, request multiple bug IDs in one
call with GET /rest/bug?id=123,456 instead of issuing one request per
bug. Keep each batch below both BMO’s request-target size limit and the search result cap. This search silently
omits bugs that do not exist or that the caller cannot see, and requests above
the result cap may also omit IDs because the results were truncated. For
batches within these limits, compare the returned IDs with the requested set
and treat missing IDs as not visible, not as deleted. In contrast,
GET /rest/bug/<id> returns an explicit error for a missing or invisible
bug.
Whenever a search is paged with limit and offset, pass a stable
order such as order=bug_id.
5.1.5. Write searches that survive configuration changes¶
Do not hard-code every open or closed status. Use status=__open__ to search
all open bugs and status=__closed__ to search all closed bugs. New workflow
statuses can then be added without breaking the integration.
Similarly, do not enumerate every resolution when searching for bugs that were
closed without being fixed. Use the custom-search parameters
status=__closed__&f1=resolution&o1=notequals&v1=FIXED. This allows new
non-fixed resolutions to be introduced without changing the integration.
When combining last_change_time with custom-search parameters, number the
f<n> charts contiguously starting with f1. Gaps in the numbering can
cause the generated change-time chart to replace an existing chart.
This documentation undoubtedly has bugs; if you find some, please file them here.