Call an API from a test
Some setup does not belong in a browser. Creating the user your test signs in as, seeding a product, resetting a counter afterwards — doing it through the UI is slow, and it fails for reasons that have nothing to do with what you are testing.
An API request step does that part directly.
Save a request on the project
Section titled “Save a request on the project”Requests live on the project, not on a single test, so several tests can share one.
- Open the Tests page and edit the project (the pencil beside the project selector).
- Find API requests and add one.
- Give it a reference — a short name like
create-user. That is what a step will point at.
If you already have the call as a curl command, paste it. The method, URL,
headers and body are filled in from it.
Call it from a step
Section titled “Call it from a step”Add a step, choose Call an API request, and put the request’s reference in the target field. Not a URL, and not a page element — the reference of the saved request.
The step passes when the response arrives with the status you expect, and fails with the status and body when it does not, like any other step.
Keep credentials out of the test
Section titled “Keep credentials out of the test”Do not paste a token into a header. Write {{env:NAME}} instead, and the agent
reads it from the environment of the machine it is running on:
Authorization: Bearer {{env:CI_TOKEN}}Two things make that safe rather than convenient:
- The agent decides what it will expose. It reads an allowlist from your own machine, never from us. Nothing is exposed by default — you list the variable names you are willing to let tests read. A request from our side to name a variable is refused, so a compromised server cannot read your environment.
- Everything it exposes is masked, unconditionally, wherever a value would otherwise appear — reports, step logs, the live runner. You do not have to mark it sensitive.
Use a value from the response
Section titled “Use a value from the response”A request can save part of the response for later steps. Give the value a name and a dotted path into the JSON:
userId ← data.user.idLater steps use it as {{userId}}, exactly like a test variable. If the value is
a token or anything else worth hiding, mark that save sensitive and it is
masked everywhere a value would be shown.
Which hosts a run may call
Section titled “Which hosts a run may call”An environment starts able to call nothing. You add the hosts it is allowed to reach.
That is the wrong way round for convenience and the right way round for safety: an environment that has not been given a destination cannot be pointed at one by accident, or by a test someone else wrote.
The list belongs to the environment, so it is checked twice against two different lists, and the difference matters:
- Saving a request needs the host to be permitted by at least one of the project’s environments — a request written for staging alone is not refused because production has never heard of that host.
- Running needs it permitted by the one environment that run resolved. So the same saved request runs against staging and is refused against production, which is the point.
A request the run’s environment does not permit never reaches the runner: the URL stays on our side, and the step fails naming both the host and the environment.
Related
Section titled “Related”- Set up the local agent — required for these steps
- Cloud vs local execution — why the cloud refuses them
- Mask passwords and other secrets — for values you type into a page
- Step actions reference — every action a step can perform