1. Docs
  2. Infrastructure as Code
  3. Pulumi CLI
  4. Calling the Cloud API

Calling the Pulumi Cloud REST API from the CLI

    The pulumi cloud api command lets you call any Pulumi Cloud REST API endpoint directly from the CLI. It runs non-interactively, is safe to script, and reuses the credentials you already use with pulumi login, so you don’t need to manage a separate token to call the API.

    The command is modeled after gh api: you pass a path, an operation ID, or a METHOD path row and the CLI handles authentication, headers, path-template substitution, and content negotiation for you.

    Subcommands

    pulumi cloud api ships in three forms:

    Authentication

    pulumi cloud api uses the same access token as the rest of the Pulumi CLI. Anything that authorizes pulumi login — a personal, organization, or team access token, PULUMI_ACCESS_TOKEN, or an OIDC-issued token — also authorizes API calls.

    If a request requires authentication and the CLI is not authenticated, pulumi cloud api exits with code 3 and an error envelope identifying the auth failure. A 401 or 403 response from the API maps to the same exit code.

    Path-template substitution

    Most Pulumi Cloud endpoints take an organization, project, or stack as part of the URL — for example, /api/orgs/{orgName}/members. pulumi cloud api resolves each template variable in the following order:

    1. A literal value typed directly into the URL (no template variable to fill).
    2. A matching -F or -f field (consumed for the path and not forwarded as a query or body parameter).
    3. The current Pulumi project context: the selected stack’s organization, the project name from Pulumi.yaml, and the selected stack name.

    When a stack is selected, you can usually call:

    pulumi cloud api ListOrganizationMembers
    

    and the CLI fills {orgName} from the selected stack automatically. When no project context is available, supply the values with -F:

    pulumi cloud api GetStack -F orgName=acme -F projectName=web -F stackName=prod
    

    If a path template and a request body field share a parameter name, the first matching -F is consumed for the path. Any subsequent -F with the same key is sent in the body, so you can pass -F twice to fill both. To keep the body fully separate, use --body or --input instead.

    Request flags

    pulumi cloud api accepts a gh api-style flag set for shaping the request:

    FlagPurpose
    -X / --methodHTTP method. Defaults to GET, or POST when body fields, --body, or --input are present.
    -F / --fieldTyped key=value. Numbers, booleans, and null are auto-detected; JSON object/array literals are parsed; @file reads from a file and @- reads from stdin. Routed as query parameters on GET/HEAD and as JSON body fields otherwise.
    -f / --raw-fieldString key=value with no type coercion. Sent verbatim.
    -H / --headerCustom HTTP header Key: Value (repeatable). User headers win over the encoder’s defaults (Accept, Content-Type); a user-supplied Authorization is dropped to keep the resolved CLI token in place.
    --bodyInline request body sent verbatim. Mutually exclusive with --input.
    --inputRead the request body from a file; - reads from stdin.
    --paginateFollow continuation cursors and emit a single combined JSON envelope. Capped at 1000 pages; on truncation, network failure, or cancellation, the partial result is flushed so callers always have something to act on.
    -i / --includeInclude the HTTP status line and response headers in the output.
    --silentSuppress the response body on success. Errors are still printed.
    --verboseDump the resolved request and the full response to stderr.
    --dry-runPrint the resolved request without sending it.
    --formatDrive content negotiation. Default uses the operation’s primary response content type (usually JSON). json or markdown request that format via the Accept header — rejected if the operation’s spec doesn’t declare it. raw keeps the operation’s default Accept and passes the response body through unchanged.

    Both requests and responses use gzip compression in transit. The CLI routes responses by content type: it pretty-prints JSON, passes text and markdown through as-is, and streams binary responses unchanged.

    OpenAPI spec caching

    The CLI fetches the OpenAPI spec once from /api/openapi/pulumi-spec.json and caches it under $PULUMI_HOME/cloud-api-cache/<host>/spec.json for 24 hours. When the cached copy is older than the TTL and a refresh fails (network error, 5xx response), the CLI returns the stale cache along with a stderr warning so transient outages don’t break list and describe.

    Pass --refresh-spec to any subcommand to force a re-fetch.

    Exit codes and error envelope

    pulumi cloud api uses the standard Pulumi CLI exit-code mapping. The values it can emit are:

    Exit codeMeaning
    0Success.
    1Caller error: bad arguments, no matching operation, missing template variable, or partial pagination.
    2Invalid flag combination (for example, --body and --input together).
    3Authentication or authorization failure (missing credentials, 401, or 403).
    8Operation canceled (SIGINT or SIGTERM).
    255Internal CLI error.

    On failure, the CLI writes errors to stderr as a single-line JSON envelope with a stable code field. Agents and scripts can parse the envelope to react to specific failure modes; tests pin the schema so it does not drift between releases.

    Examples

    Basic requests

    Inspect the currently authenticated user:

    pulumi cloud api /api/user
    

    Call by URL path with template variables filled from -F:

    pulumi cloud api /api/orgs/{orgName}/members -F orgName=acme
    

    Call by operation ID — orgName is taken from the current Pulumi project:

    pulumi cloud api ListOrganizationMembers
    

    Pass path variables explicitly when no project context is available:

    pulumi cloud api GetStack -F orgName=acme -F projectName=web -F stackName=prod
    

    Bodies and fields

    Create a resource via POST; body fields are auto-detected from the operation:

    pulumi cloud api CreateOrgToken -F orgName=acme \
      -F name=ci-bot -F description="CI deploy token" \
      -F admin=false -F expires=0
    

    Send a nested JSON body by mixing scalar fields with an inline JSON literal:

    pulumi cloud api CreateStack -F orgName=acme -F projectName=web \
      -F stackName=prod -F 'tags={"env":"prod","team":"platform"}'
    

    Pass an entire request body inline, or read it from a file or stdin:

    pulumi cloud api UpdateStackTags -F orgName=acme -F projectName=web -F stackName=prod \
      --body '{"env":"prod","team":"platform"}'
    
    pulumi cloud api UpdateStackTags --input ./tags.json
    
    cat tags.json | pulumi cloud api UpdateStackTags --input -
    

    Filtering and pagination

    Filter the JSON response with jq:

    pulumi cloud api /api/user --format=json | jq '.githubLogin'
    

    Walk every page of a paginated endpoint:

    pulumi cloud api ListUserStacks --paginate | jq -r '.stacks[].stackName'
    

    Discovery and dry-run

    Browse the API surface and inspect a specific operation:

    pulumi cloud api list --format=json | jq '.operations[] | select(.tag == "Stacks")'
    
    pulumi cloud api describe CreateOrgToken --format=markdown
    

    Preview the resolved request without sending it:

    pulumi cloud api CreateOrgToken -F orgName=acme \
      -F name=ci-bot -F description="CI" -F admin=false -F expires=0 --dry-run
    

    See also