Last reviewed: November 12, 2026 (Asia/Shanghai); primary references fetched November 11 UTC.
Direct answer
For a Bruno CometAPI setup, save a POST request to the documented Chat Completions endpoint, put its base URL and model ID in an environment, and store the API key as a Bruno secret variable. Reference that secret in the Bearer Token authentication field. Add response tests that require a completed assistant text answer before treating the check as successful.
The CometAPI Chat Completions reference defines the endpoint and response fields. Bruno’s secret-variable documentation explains that environment files retain secret names while their values stay in a local encrypted store. Together, these let you share a request definition without embedding its credential.
Who this is for
This tutorial is for developers and support engineers who want a desktop API-client check before integrating CometAPI into application code. You need an installed Bruno v4 desktop app, an empty local collection, and a CometAPI credential with access to a suitable chat model.
The procedure follows current official documentation. No Bruno desktop session or authenticated CometAPI request was run for this article. The JavaScript assertions were checked separately against synthetic response fixtures; those checks do not establish desktop integration or account access.
Key takeaways
- Keep the shared request definition separate from the local credential value.
- Use the full operation path once; an SDK base URL alone is not the request endpoint.
- Put only the secret reference in Bruno’s Token field; Bruno supplies the
Bearerprefix. - Start with one non-streaming request and a harmless prompt.
- Test response structure and completion status, rather than exact generated wording.
- Treat every deliberate resend as another potentially billable operation.
Configure the environment and secret
Use a dedicated, empty collection named CometAPI manual check in a private local directory. This keeps unrelated collection scripts, inherited authentication, and request presets out of the initial check. Inspect any collection you reuse before giving its scripts access to a live credential.
Following Bruno’s Environment Variables guide
, open the environment selector at the top right and create an environment named live-manual. Add these ordinary variables:
| Name | Value | Purpose |
|---|---|---|
COMETAPI_BASE_URL | Copy the SDK base URL from the CometAPI reference | HTTPS, host api.cometapi.com, path /v1, without a trailing slash |
COMETAPI_MODEL | gpt-6-astra | Model used in the current CometAPI basic chat example |
The body below follows that documented model example. Confirm its availability for your account before sending. If you select another model, review its supported endpoint and parameters before retaining the reasoning and output-limit fields.
Open this environment’s Secrets tab and add COMETAPI_KEY with your credential as its value. Save the environment and explicitly select live-manual for the request. Bruno documents the separate Secrets tab from v4.0.0; older installations can have a different interface.
Do not create the key as an ordinary environment variable. The secret-variable reference says secret values stay in Bruno’s local encrypted store and are omitted from collection-file exports. That protection depends on using the secret-variable mechanism: pasting the same value into a header, script, description, or ordinary variable creates another copy outside it.
Bruno’s environment guide
documents {{varName}} interpolation and shows the selected environment in the interface. Before continuing, check the selection and look for conflicting definitions of these names in a reused collection. This workflow needs no parent environment or shared default.
The site’s repository key-handling guide provides the related checks for copied snippets and configuration files.
Build the saved chat request
Bruno’s Create a Request guide
documents creating a request from a collection’s menu. Choose New Request, select HTTP, name it Chat text check, and set the method to POST. Use this URL:
{{COMETAPI_BASE_URL}}/chat/completions
With the environment above, the request uses HTTPS on host api.cometapi.com and path /v1/chat/completions. Keep /v1 in the base and /chat/completions in the request, as shown in the documented operation
. Duplicating either segment sends a different path.
In Auth, select Bearer Token. Enter this in the Token field:
{{COMETAPI_KEY}}
Do not include the word Bearer in that field. The Bruno Bearer-authentication reference
says Bruno constructs the Authorization header by adding the prefix. Remove any manually entered Authorization header so the request has one intended authentication configuration.
In Headers, set Content-Type to application/json. In Body, select the JSON option under RAW, as described in Bruno’s Body Data guide
, and enter:
{
"model": "{{COMETAPI_MODEL}}",
"messages": [
{
"role": "user",
"content": "Explain idempotency in one short sentence."
}
],
"reasoning_effort": "low",
"max_completion_tokens": 2048,
"stream": false
}
The CometAPI reference documents these fields for its example model. The 2,048-token ceiling is an illustrative starting choice. It includes reasoning and visible output, so it does not promise 2,048 visible tokens or completion of every prompt. Keep model-specific sampling settings out of this baseline.
Save the request. Keep collection, folder, and request hooks free of extra HTTP calls or chaining for this first check. Use the individual request’s Send action after completing the review below; running a whole collection can execute additional requests.
Add tests for completed text
Open the request’s Tests tab and paste this script. Bruno’s Testing guide
documents test, Chai expect assertions, and the response methods used here.
test("HTTP 200 with JSON media type", function () {
expect(res.getStatus()).to.equal(200);
const mediaType = String(res.getHeader("content-type") || "")
.split(";")[0].trim().toLowerCase();
expect(mediaType).to.equal("application/json");
});
test("one completed assistant text answer", function () {
expect(res.getStatus()).to.equal(200);
const body = res.getBody();
expect(body).to.be.an("object");
expect(body.object).to.equal("chat.completion");
expect(body.choices).to.be.an("array").with.lengthOf(1);
const choice = body.choices[0];
expect(choice).to.be.an("object");
expect(choice.finish_reason).to.equal("stop");
expect(choice.message).to.be.an("object");
expect(choice.message.role).to.equal("assistant");
expect(choice.message.content).to.be.a("string");
expect(choice.message.content.trim().length).to.be.above(0);
expect(choice.message.refusal == null).to.equal(true);
expect(choice.message.tool_calls == null).to.equal(true);
});
These are the acceptance rules for this text-only check. They require exactly one choice, assistant text, a stop finish reason, and an absent or null refusal and tool-call field. Other valid API outcomes need different handling. A length-limited response or a tool call should fail this check even when the server returned HTTP 200.
The script deliberately avoids asserting that the answer equals a particular sentence. Model wording can vary while the response still satisfies the intended structure. It also leaves room for additional response properties instead of demanding an exact set of object keys.
Tests evaluate the returned response; they do not prevent the request from being sent or impose a financial limit. A failed assertion can follow a billable generation. Keep test output private until reviewed, since assertion diagnostics can include response values.
Contract details to verify
Before clicking Send, review the selected environment, resolved destination, secret reference, JSON body, and empty script hooks. Send the individual request once, then inspect its response and test results.
| Boundary | Required observation | What to do if it differs |
|---|---|---|
| Destination | HTTPS on api.cometapi.com, path /v1/chat/completions | Correct the base or operation path before sending |
| Credential | Token field references COMETAPI_KEY; no pasted key or duplicate Authorization entry | Repair local configuration without sharing the resolved header |
| Model | The reviewed model ID and its supported parameters are selected | Recheck the model-specific request contract |
| HTTP response | Status 200 with JSON media type | Classify the HTTP or response-format failure |
| Completion | Both tests pass, with one completed text choice | Inspect finish reason, refusal, and content shape |
| Usage evidence | Inspect the returned usage fields when present | Record missing evidence explicitly; do not infer zero usage |
Retain the observation time, installed Bruno version, request name, selected model, HTTP status, assertion results, and completion category. Record usage values only as observed. Avoid copying the credential, resolved request headers, prompt text, or full response into a shared troubleshooting note.
For the assertion script’s local fixture check, a synthetic completed response passed both tests. Separate fixtures with HTTP 401, HTML media type, malformed completion structure, empty choices, a length finish reason, blank text, a refusal, or tool calls each caused at least one test to fail. This verifies the assertions’ behavior under those supplied inputs. It does not reproduce Bruno’s transport, interpolation, or response parsing.
Before sharing the collection, inspect its saved files and an export for literal credentials and private text. A secret-variable export omits the secret value; it does not sanitize a value pasted elsewhere. The recipient must provision their own local secret and verify the active environment.
Failure modes
Authentication fails. Check the selected environment, the locally populated secret, and the Token field. A saved secret name without its local value is incomplete configuration. Do not paste a resolved Authorization header into a support ticket.
A request-shape problem looks like a server outage. Compare the method, path, and body with the CometAPI reference. Its documented 500 examples include a missing messages field, so the status alone cannot identify the cause. Inspect any error body privately before deciding to resend.
HTTP 200 appears successful, but the text check fails. Review object, choices, finish_reason, and the assistant message. Do not turn a refusal or truncated result into accepted text by removing assertions simply to obtain green indicators.
The response is an event stream. Confirm stream is the Boolean false and inspect any script that modifies the body. This script expects a complete JSON completion; SSE needs separate event handling and tests.
The request times out. Preserve the observation before another Send. The remote operation may have progressed even though the desktop client lacks a completed response. This procedure adds no retry loop, and the response assertions establish no cancellation or duplicate-suppression guarantee.
A collection works only on its author’s machine. Check the recipient’s local secret provisioning, environment selection, installed version, and model access. Sharing the file does not transfer the encrypted local credential value.
Sources checked
Seven primary public references returned HTTP 200 on November 11, 2026 UTC, corresponding to November 12 in Asia/Shanghai:
- CometAPI: Create a chat completion — endpoint, Bearer authentication, model example, request fields, completion outcomes, usage, and error examples.
- Bruno: Create a Request — saved collection requests and HTTP method, URL, and editor setup.
- Bruno: Body Data — selecting a raw JSON request body.
- Bruno: Environment Variables — environment creation, selection, interpolation, and file persistence.
- Bruno: Secret Variables — v4 Secrets tab, local encrypted storage, secret names in environment files, and export behavior.
- Bruno: Authenticate with a Bearer token — Token-field variables and automatic Bearer-prefix construction.
- Bruno: Testing — JavaScript response tests, Chai assertions, status, headers, and body access.
These maintained technical references support an evergreen integration task. Bruno’s current documentation describes v4; compare the steps with your installed release. The narrow text acceptance rule and manual review sequence are recommendations built from the documented interfaces.
FAQ
Can I share the collection without sharing my key?
Bruno documents that secret-variable values remain local and are omitted from collection-file exports. Review the other saved fields and files too, then have each recipient populate their own secret. Ordinary variables and literal headers do not gain that protection automatically.
Do passing tests prove the generated answer is correct?
They establish the structural conditions encoded in this script for the observed response. Review the answer’s factual quality separately. The tests also do not establish pricing, account-wide availability, or performance under load.
Should this collection run automatically in CI?
Keep this credential-backed manual check separate from routine offline tests. For a Node.js application, the site’s Undici MockAgent tutorial provides a different workflow for testing request construction and failures with synthetic responses.
Reader next step
Save one request, review its active environment and authentication reference, and perform one small manual check. Keep the actual test results and usage observations with your local setup notes, then inspect the collection files before sharing them.
Need a credential for that first account-backed request? Start with CometAPI , then return to the same saved request and verification steps.