Nexus API reference
Connect test automation, CI pipelines and deployment systems to the quality record inside Jira.
API v1
Use two project-specific endpoints: one receives framework result files; the other accepts bounded JSON operations for tests, cycles, runs, environments and test data.
Start here
- In Jira, open Nexus Project Settings → API Keys & CI.
- Create an API key and copy it. Nexus shows the key once.
- Copy the Results URL or CI API URL shown for the project.
- Store the URL and key in your CI system's secret store.
- Send the key in the
Authorizationheader. Never put it in a URL or pipeline file.
Authorization: Bearer <NEXUS_API_KEY>
Keys belong to one Jira project, and a project can have up to 10 active keys. A project administrator can restrict a key to sending results, using the CI API, using the automation runner, or a combination. Revoking one key does not affect the others. Nexus stores only a salted hash and never returns the key again.
HTTPS only. Both URLs are https:// addresses on Atlassian's platform. Send the key
only over HTTPS, and never let a client follow a redirect with the key attached (with
curl, leave out -L). The Nexus reporters, the nexus-upload CLI, the GitHub Action
and the automation runner refuse a plain http:// Nexus URL before sending anything, and
they never follow redirects. The one exception is for local tests:
NEXUS_ALLOW_INSECURE_LOCALHOST=1 allows http to localhost, 127.0.0.1 or [::1]
only.
Upload JUnit, Cucumber, Playwright and other framework reports.
Send one or more JSON operations, with a maximum work budget of 25.
Send automated results
Post the result file as the request body. Nexus detects the format when possible and matches each result to the Test Case whose Automation Key starts the test name. Unknown keys are reported as unmatched; Nexus never guesses.
curl --fail --silent --show-error -X POST \
"$NEXUS_RESULTS_URL?project=NEX&environment=staging&build=4821&commit=a1b2c3d" \
-H "Authorization: Bearer $NEXUS_API_KEY" \
-H "Content-Type: application/xml" \
--data-binary @results.xml
Supported formats
format value |
Common producers |
|---|---|
junit-xml |
JUnit, PyTest, NUnit, TestNG, Robot Framework, Playwright JUnit reporter |
cucumber-json |
Cucumber |
playwright-json |
Playwright JSON reporter |
mocha-json |
Mocha |
mochawesome-json |
Mochawesome |
xunit-xml |
xUnit.net v2 |
robot-xml |
Robot Framework native output |
nunit-xml |
NUnit native output |
testng-xml |
TestNG native output |
newman-json |
Postman collections run with Newman (-r json) |
json |
Nexus plain JSON format |
For Newman, each request is one result. A failed assertion, a script error or a request that could not be sent is a failure. A request whose tests were all skipped is Blocked.
Result query parameters
| Parameter | Purpose |
|---|---|
project |
Required Jira project key. It must match the API key's project. |
environment |
Environment name or configured alias such as stg. |
build |
Build or pipeline identifier. |
commit |
Source revision. |
component |
Component or service under test. |
testSet |
Record results against a particular execution cycle. |
configuration |
Nexus Test Configuration id. |
dataSet |
Dataset id for results named with a row key such as login [cust-3]. |
format |
Explicit parser when detection is not suitable. |
systemOut |
comment posts each JUnit test's own <system-out> as a plain-text comment on its run, cut to 8,000 characters, for at most 50 results an upload. The comment mentions and notifies no one. Off by default; JUnit XML only. |
stepMatching |
off records one overall result per Test Case and leaves its design steps unmarked. By default (on), the overall outcome is spread over the case's steps. |
job |
Automation-runner job id. The supplied Nexus runner sets this value; don't set it yourself. A job id that is malformed, unknown, expired, finished, or held by another runner key is refused with 400. It never falls back to ordinary ingestion. |
The Results endpoint accepts up to 5 MB and 120 requests a minute per project. It
responds with 202, 400, 401, 413 or 500 and a small JSON status body; see
Responses. Result-level detail and unmatched names
appear in the Ingestion log and Unmatched results on Project Settings → API Keys
& CI.
Resending and large uploads
Resending the same upload is always safe. Nexus fingerprints each upload: the file plus
the parameters that change what it does (project, format, testSet, configuration,
environment, build, commit, component, dataSet, job, systemOut). It never
records a result of the same upload twice.
- Nexus processes up to 500 results per request within the platform's time limit. If it
runs out of time part-way, it answers
202with{"status":"partial","reason":"time budget reached; send the same upload again to continue"}. Send the same file with the same parameters again, and repeat until the answer is{"status":"accepted"}. Each resend carries on where the last one stopped.partialalso means another send of the same upload is still running. - Parallel shards that post results for the same Test Case land on one Test Execution.
- To record a deliberate re-run of an identical report, change
build(for example, a new pipeline number). With the samebuild, the upload is treated as the same one for 6 hours. Withoutbuild, an identical report sent more than 5 minutes after the first one finished counts as a new run. curl --retrydoes not resend a202. For large suites, use a packaged integration (they resendpartialfor you) or loop. The CI guide has a loop example.
Use the CI API
The CI API receives one JSON object containing an operations array. Each operation's
top-level fields use a strict allow-list. An unknown operation field or invalid shape rejects the whole request
before work starts.
curl --fail --silent --show-error -X POST \
"$NEXUS_CI_API_URL?project=NEX" \
-H "Authorization: Bearer $NEXUS_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"operations": [
{
"op": "create-test-case",
"summary": "Login with valid credentials",
"automationKey": "AUTH-LOGIN-01",
"externalKey": "build-4821-login"
},
{
"op": "report-result",
"automationKey": "AUTH-LOGIN-01",
"status": "passed",
"environment": "staging"
}
]
}'
Operations
| Operation | Required fields | Purpose |
|---|---|---|
create-test-case |
summary |
Create a Jira Test Case, optionally with steps, preconditions and an Automation Key. |
update-test-case |
testCaseKey |
Replace supplied design fields on an existing Test Case. |
add-to-cycle |
testSetKey, testCaseKey |
Add one Test Case to an execution cycle. |
add-cases-to-cycle |
testSetKey, testCaseKeys |
Add up to 25 Test Cases and log an outcome for each case. |
set-run-assignee |
runKey, accountId |
Assign a Test Execution, or use null to unassign it. |
report-result |
automationKey, status |
Record one automated result using the same execution path as file ingestion. |
record-deployment |
environment, version, status, externalId |
Record an idempotent deployment. |
record-environment-event |
environment, type, externalId |
Record an outage, refresh or other environment event. |
record-configuration |
environment, entries, externalId |
Capture an environment configuration snapshot. |
reserve-data-rows |
execution, dataSet, externalId |
Reserve consumable test-data rows for a pipeline. |
consume-data-rows |
execution, dataSet, externalId |
Mark reserved rows as used. |
release-data-rows |
execution, dataSet, externalId |
Return reserved rows to the available pool. |
Test design operations
create-test-case accepts:
summary: required, up to 255 characters.steps: up to 100{ action, data, expected }rows; each cell is bounded to 4,000 characters.preconditions: up to 4,000 characters.automationKey: up to 200 characters. Use only letters, digits and_ . : @ / -, with no spaces, and don't start it with-. Any other key fails the whole request with400. The same rule applies toupdate-test-caseand to Jira's own edit screens.externalKey: up to 200 characters. Reusing it makes retries idempotent. This holds even when two deliveries of the same batch arrive at the same time: only one creates the Test Case, and the other logsidempotent-hit, orin-progressif the first is still creating it.
update-test-case accepts testCaseKey plus steps, preconditions or
automationKey. When supplied, steps replaces the complete step table; it does not
merge rows.
{
"operations": [
{
"op": "create-test-case",
"summary": "Customer completes checkout",
"automationKey": "CHECKOUT-01",
"externalKey": "catalog-checkout-v3",
"preconditions": "A customer has one product in the basket",
"steps": [
{
"action": "Submit the saved delivery address",
"data": "Standard delivery",
"expected": "The payment step opens"
}
]
}
]
}
Cycle and run operations
add-cases-to-cycle.testCaseKeys contains 1–25 unique Jira issue keys. Each key counts
as one unit of the request's 25-operation work budget. Obsolete Test Cases and closed
cycles are refused without changing Jira.
set-run-assignee.accountId is an Atlassian account id or null. The run must be a
Test Execution in the authenticated project and its cycle must be open.
report-result.status is one of passed, failed, skipped or blocked. Optional
fields are actualResult, environment, testSetKey and configurationId.
Deployments and environment evidence
{
"operations": [
{
"op": "record-deployment",
"environment": "staging",
"version": "2.5.0",
"status": "success",
"externalId": "deploy-4821",
"build": "4821",
"commit": "a1b2c3d",
"component": "checkout-api"
},
{
"op": "record-environment-event",
"environment": "staging",
"type": "refresh",
"invalidatesResults": true,
"externalId": "refresh-2026-09-27",
"note": "Synthetic customer accounts refreshed"
}
]
}
Deployment status is success, failed or rolled_back. Optional fields are
release, component, build, commit, deployedAt and evidenceUrl.
Use an ISO-8601 timestamp for deployedAt; it cannot be more than five minutes in the
future. evidenceUrl, when supplied, must use HTTPS.
Environment-event type is refresh, outage_start, outage_end, config_change
or health. A health event requires healthState, which is healthy, degraded,
down or unknown; other event types must omit healthState. Other optional fields
are invalidatesResults, occurredAt and note. occurredAt is an ISO-8601 timestamp
and cannot be more than five minutes in the future.
record-configuration.entries is a string-to-string object with up to 100 entries.
Keys contain up to 64 letters, numbers, dots, underscores, colons, slashes or hyphens,
and must begin with a letter or number. Values contain 1–256 printable, single-line
characters. Optional fields are merge, capturedAt and note. capturedAt is an
ISO-8601 timestamp and cannot be more than five minutes in the future. A merge requires
at least one entry. Nexus rejects keys or values that look like secrets.
Consumable test data
Use the same execution and externalId across reserve, consume and release operations.
execution must be a Test Execution in the authenticated project. A reservation belongs
to that execution and externalId: another pipeline or execution cannot consume or
release its rows, and results posted to the Results URL use up only reservations made
for the same Test Execution. A reservation requires exactly one of count (1–200) or
rowKeys (up to 200). environment is optional and selects the correct pool for an
environment-scoped dataset.
Retrying a reservation with the same externalId renews the rows the pipeline still
holds. It does not take back rows whose lease already ran out. Those can be reserved
again only if nobody else has reserved them in the meantime.
{
"operations": [
{
"op": "reserve-data-rows",
"execution": "NEX-246",
"dataSet": "4ed07d8c-4418-4c3a-8a42-9b11cdd8d4cb",
"externalId": "build-4821",
"count": 5,
"environment": "staging"
}
]
}
Limits and processing
| Limit | Value |
|---|---|
| CI API request body | 512 KB |
| Work budget per request | 25 operations |
| Concurrent operation workers | 3 |
| Stored CI operation history | Up to 100 batches per project |
| Result-ingestion body | 5 MB |
Operations run independently after request validation. One operation failing does not
stop the remaining valid operations. The HTTP response confirms only that the batch was
accepted. Nexus records each operation's outcome (ok, idempotent-hit or failed with
a short failure code) in its CI operation log for the project. A project admin reads it
in Project Settings → CI → CI API log: the last 100 calls, newest first, with each
operation's outcome, failure code, externalKey and the Test Case it created or updated,
and a failures-only filter. The failure codes
include in-progress (another delivery of the same externalKey is still creating the
Test Case; retry later), reconcile-uncertain and idempotency-unavailable. With these
last two, nothing was created; retry later.
externalKey and externalId make retried writes idempotent. The endpoint's responses
are fixed and cannot return created Jira issue keys. When a pipeline must find a Test Case
it created, use your own Jira REST credentials. Every Test Case created with an
externalKey carries it in the ciExternalKey issue property from the moment it exists.
The property can't be searched with JQL. Search the project's Test Cases with
properties=ciExternalKey and match the value that comes back.
Responses and troubleshooting
| Status | Meaning | What to do |
|---|---|---|
202 Accepted |
The request was authenticated, validated and dispatched. Body: {"status":"accepted"}. |
Check the Ingestion log for result-level outcomes. |
202 Accepted (partial, Results URL only) |
Nexus kept what it recorded but has not finished this upload, because its time limit ran out or another send of the same upload is still running. Body: {"status":"partial","reason":"time budget reached; send the same upload again to continue"}. |
Send the same file with the same parameters again until the answer is accepted. See Resending and large uploads. |
400 Bad Request |
JSON, report format, query parameters or an operation shape is invalid. Body: {"status":"rejected","reason":"invalid payload"}. |
Correct the request before retrying. |
401 Unauthorized |
The key is missing, invalid, revoked or belongs to another project. Body: {"status":"rejected","reason":"unauthorized"}. |
Check the secret and project key. |
413 Payload Too Large |
The byte limit, parsed-result limit, operation work budget or per-project rate guard was exceeded. Body: {"status":"rejected","reason":"payload too large"}. |
Split oversized payloads or batches. If the request rate is high, wait and retry with bounded backoff. |
500 Internal Server Error |
Nexus could not accept the request. Body: {"status":"error"}. |
Retry with bounded backoff, then include the timestamp when contacting support. |
Common result-ingestion problems:
- Unmatched test: put the Test Case's Automation Key at the start of the test name.
- Unknown environment: use the configured environment name or alias.
- No result after a failed test job: make the upload step run even when tests fail.
- Accepted CI API batch with a failed operation: the HTTP response cannot carry per-operation detail. Check the result in Jira, or contact support with the request time.
400withjob=set: the runner job has finished, expired or belongs to another runner key. Let the runner queue the work again; don't reuse an old job id.partialagain and again: make sure every resend is the identical file with the identical parameters. A changedbuildorenvironmentstarts a new upload.
Automation runner
The customer-hosted nexus-runner (download it from the Integrations
page) takes automation runs queued from a cycle and runs the tests on
your own machine or CI agent. Tests never run inside Jira or Forge. The runner uses a
third project URL, shown on Project Settings → API Keys & CI, and a key with the
runner scope.
- Runner automation is a Beta feature. It is off by default for a project with no automation history; turn it on in Project Settings → Modules → Runner automation. While it is off, the runner URL refuses the project. Posting results from CI (the two URLs above) keeps working either way.
- The runner posts its results to the Results URL with
job=<id>, using the same API key that claimed the job. Heartbeats and completion from any other key are refused (409). - Nexus never sends a Test Case whose Automation Key breaks the rule above (letters,
digits and
_ . : @ / -) to a runner. Those runs are flagged instead. - The runner's own API is managed by the runner and not listed here. Keep the runner up to date: newer Nexus releases can require a minimum runner version.
Compatibility and support
Nexus may add optional fields and new operation kinds without breaking existing clients. Removing or renaming a published field, operation or response status requires a documented major-version change.
For copy-paste GitHub Actions, GitLab CI, Jenkins, Azure Pipelines and Bitbucket examples, use the CI guide. For reporter downloads and the Nexus automation runner, use the Integrations page.
For help, email nexus-support@resync.co.nz with the Jira site, project key, UTC/NZ timestamp and, for a results upload, the reason shown in the Ingestion log. Never send an API key.