Skip to content

Integrations

Atlassian Jira SDK: get started

The complete Atlassian Jira API through typed application or agent clients

Use an ordinary App, or an Agent when the workload needs agent identity. Alter builds provider requests from a reviewed contract and applies the same connection authorization, policy, approvals, and audit records as raw requests.

Terminal window
npm install @alter-ai/sdk @alter-ai/atlassian
# Python (installs core automatically)
pip install alter-sdk-atlassian

The provider package includes only Atlassian Jira types and response schemas and pins its contract version.

Configure Atlassian, request the Jira scopes the application needs, and retain each customer’s grant ID after Connect consent. Alter supplies the credential; it never belongs in operation input. The managed provider is atlassian because Jira calls use the Atlassian connection: an existing Atlassian grant calls these operations without a new OAuth app.

Every operation names one Atlassian site by its cloud id, in path.cloudId. A user can grant one connection access to several sites, so choose the site per call. The sites a grant can reach, with their id and url, come from Atlassian’s accessible-resources endpoint through the application client:

import { App } from "@alter-ai/sdk";
import { AtlassianIntegration } from "@alter-ai/atlassian";
const app = new App({ apiKey: process.env.ALTER_API_KEY! });
try {
const grantId = process.env.ATLASSIAN_GRANT_ID!;
let response = await app.proxyRequest({ method: "GET", url: "https://api.atlassian.com/oauth/token/accessible-resources", grantId });
if ("status" in response) {
for (const gate of response.gates) console.log("Approval required:", gate.approvalUrl);
response = await app.awaitApproval(response.approvalId);
}
const sites = response.bodyJson() as Array<{ id: string; url: string }>;
const client = new AtlassianIntegration(app, { grantId });
const result = await (await client.myself.getCurrentUser({ path: { cloudId: sites[0].id } })).wait();
console.log(result.bodyJson());
} finally {
await app.close();
}
from alter_sdk import App, PendingApproval
from alter_sdk_atlassian import AtlassianIntegration
async def first_call(api_key: str, grant_id: str):
async with App(api_key=api_key) as app:
response = await app.proxy_request("GET", "https://api.atlassian.com/oauth/token/accessible-resources", grant_id=grant_id)
if isinstance(response, PendingApproval):
for gate in response.gates:
print("Approval required:", gate.approval_url)
response = await app.await_approval(response.approval_id)
sites = response.body_json()
client = AtlassianIntegration(app, {"grant_id": grant_id})
call = await client.myself.get_current_user({"path": {"cloudId": sites[0]["id"]}})
result = await call.wait()
return result.body_json()

A cloud id is a UUID; any other value is refused before a request is sent. Atlassian refuses a site the grant was not given, so a cloud id never widens what a connection can reach. A policy rule can still limit an agent to particular sites with a condition on the cloudId parameter.

Contract 2026-10-28 contains the 597 operations of Atlassian’s official Jira Cloud platform REST API v3 document that an OAuth connection can call. The API reference links every operation to its complete input fields, response models, TypeScript and Python examples, and policy identity. Browse by resource under this provider’s API reference in the Integrations sidebar, or download the pinned OpenAPI specification. The Developer Portal provider view and alter integrations operations atlassian --version 2026-10-28 also expose the schemas.

Generated calls pin the Alter contract version. Atlassian Jira’s own product, role, scope and subscription requirements still apply. There is no silent version fallback and no automatic write retry or pagination.

Terminal window
alter integrations execute atlassian atlassian.getcurrentuser \
--version 2026-10-28 --grant "$ATLASSIAN_GRANT_ID" \
--input '{"path": {"cloudId": "11223344-a1b2-3b33-c444-def123456789"}}' --wait

Arguments use native path, query, headers, and body containers. Array query parameters are sent the way the provider’s document declares them: one delimited value where it declares explode: false (or a pipe- or space-delimited style), repeated keys otherwise. SDK methods preserve provider field names, decimal lexemes and large integers as strings when necessary. HTTP 204 returns null / None from the typed decoder. Binary responses use bodyBytes() / body_bytes(); the CLI can save them with --output-file.

A policy rule can require approval for any operation. The call returns a pending approval; wait() resolves once the approver decides, and resume(approvalId) picks a pending approval up after a restart. Approval cards show the operation, its contract version and the request input the sensitivity review marked safe to display.

Every binary input is a JSON object with filename, content_type, and content_base64. Adding attachments (issueAttachments.addAttachment / issue_attachments.add_attachment) takes one such object, or an array of them, in body.file; Alter sends each as a file part of a multipart request. Loading a project, issue type or priority avatar takes one object in body, a JPEG, GIF or PNG image, and Alter sends its bytes with that media type. Setting filter, user or navigator columns takes body.columns, an array of field ids, sent as repeated form fields. Setting a user preference takes the value as a string body, sent as plain text. Alter adds the X-Atlassian-Token: no-check header these operations require.

The shared proxy accepts up to 5 MiB of serialized input and encoded upload data; base64 adds overhead, so accepted file bytes are smaller than that ceiling. Attachments are classified sensitive. Under a require_approval rule an attachment upload is held for approval like any other request, and the approval page shows the attachment masked as its file name and size, never its contents. Approval pages for other operations show the exact semantic fields, and avatar uploads show the file name, media type, byte length and SHA-256 digest, never the image. Frozen execution uses the stored input and the original contract, rechecks current authority, and never replays an uncertain write.

Every write has a reviewed family entry, decided from Atlassian’s documentation of that operation; an unreviewed new write fails generation. Operations that need the manage:jira-configuration, manage:jira-project or manage:jira-webhook scope, or that change permissions, roles, issue security levels, sharing, users or groups, include admin. Operations that remove something (delete, remove, archive, trash, replace, merge a version) include delete. Operations that email people include send: the ones with a notifyUsers option (editing an issue, updating a comment, adding, updating and deleting a worklog), the bulk delete, edit, move and transition operations (their sendBulkNotification field), the issue writes that fire an event Jira’s default notification scheme emails (assigning and deleting an issue, deleting a comment, adding an attachment), sending an issue notification, exporting archived issues, setting a project’s sender email, creating a user, and the writes whose rich text notifies @-mentioned users (creating, bulk creating, editing and transitioning an issue, adding and updating a comment). Lookups Jira serves as POST (JQL search, bulk fetch, bulk permission checks, parsing and evaluating expressions) are read; configuration lookups and dry runs served as POST (bulk workflow and workflow-scheme reads, workflow preview and validation, workflow history, JQL sanitizing, custom field configuration and context mapping, required status mappings, panel pin status, policy validation) are admin and read. Starting Rovo agent sessions on issues is send and write, since an agent working an issue may update it and its watchers. No operation moves money, so none carries payment. Setting a project’s sender email also exposes the address as the sender parameter, and registering dynamic webhooks exposes the delivery address as the url parameter, so a rule can bind where Jira sends issue events. Other Jira bodies are open-ended (custom fields, rich text), so rules bind those operations by operation and family.

Reading the sites a grant can reach (accessible-resources) and the signed-in account (/me) are cataloged as read, so an operation-scoped rule does not refuse the first step. For a grant whose scopes are narrowed, each operation is held to the scope Atlassian documents for it; a narrowed grant pinned to routes by its own restriction rule keeps its route pinning.

Payload capture follows the application’s capture setting, on managed and raw proxied calls alike: credentials are removed, every field Alter’s reviewed inventory for the provider marks sensitive is masked in requests and responses, including fields it locates only by operation, and binary bodies, calls that can return a credential and calls carrying raw card data are never stored. Metadata audit is unchanged. Attachment bytes and the password field of user creation are held encrypted with a pending approval and shown masked to the approver; they never appear in logs and are masked in payload capture. Comments, issue fields, pagination cursors and other content remain available to approvers.

Thirty-three operations in Atlassian’s document are not published because an OAuth connection can never call them: they accept only basic auth or Connect app authentication, or Atlassian documents them as available only to Connect or Forge apps, or only to the app that owns the data (app properties, UI modifications, dynamic modules, Connect migration, app custom-field values, JQL function precomputations, redaction, user email lookups, setting the user’s locale, and two internal worklog and rule endpoints).

Fault detection follows Atlassian’s successful-response schemas: starting agent sessions (batch or uniform) answers 200 with per-item outcomes, and a success of false means no session started, so ok is false and bodyJson() / body_json() raises; the per-item outcomes stay readable through bodyBytes() / body_bytes(). Ordinary errors use HTTP error statuses.

Changes for existing Atlassian connections

Section titled “Changes for existing Atlassian connections”

The policy catalog covers Jira Cloud platform REST API v3 only, at the API gateway (/ex/jira/{cloudId}/rest/api/3/...), plus the two gateway reads above. Requests to /rest/api/2/, Jira Software (agile) and Jira Service Management APIs, and Confluence are not classified: an operation, family or content rule fails closed for them, as it did for every Atlassian request before.

The same catalog also classifies requests that applications already send to the Jira v3 API through the generic request methods. Applications with Atlassian connections see these changes on those requests:

  • Rules now evaluate instead of failing closed. Before, no Atlassian request was classified, so a rule naming an Atlassian operation, family or content condition refused every Atlassian request. Now each Jira v3 request is matched to its operation: a family rule applies only to operations in that family, and deny or content rules no longer block reads they do not name. Review rules written to block all Atlassian traffic and widen them (for example, a host or provider rule) if that is the intent.
  • Sensitive input is held and masked. Under an approval rule, a raw attachment upload or user creation now creates a pending approval with the sensitive values masked for the approver; earlier releases refused it with sensitive_input_not_retained. See Sensitive input in approvals.
  • Narrowed grants are checked per operation. A grant whose scopes are narrowed, with no restriction rule pinning its routes, was refused every Jira request with scope_narrowing_unenforceable. Each request is now allowed when the narrowed scopes include the operation’s documented scope, and refused with insufficient_scope otherwise. Grants pinned by their own restriction rule, and connections’ declared scopes, behave as before.
  • The served API specification for the Atlassian connection lists the Jira v3 operations at their gateway paths (/ex/jira/{cloudId}/rest/api/3/...).

Approval-gated requests the catalog does not classify, including Confluence, are not refused for their field names.

The pinned official source, its hash, the generated methods and the policy mapping are checked together. Scheduled checks save upstream candidates and report additions, removals and schema changes; they never replace a published contract automatically. Existing contract versions remain available for installed SDKs and pending approvals.

Persist call.approvalId (TypeScript) or call.approval_id (Python), then construct a fresh provider client and call resume(savedId), followed by wait(). The stored approval selects the operation; this installed package verifies its provider and contract version before attaching the response validator. Mismatches raise ManagedOperationError, never silently decode using another contract. See persist-and-resume examples.

Policy operation fields also accept the published SDK function IDs listed by alter integrations operations atlassian. Use when.operation for a json_match or conditional require_approval rule, or match.operations for content_match (including redaction and step-up). Conditional approval can also use when.match.operations with parameter conditions. alter policy simulate --operation <function-id> tests that exact function.

Managed calls carry a server-verified function identity. Alter still evaluates policy against the actual method, URL and body after building the request from the authorized connection. Existing endpoint, method, host, catalog-operation and family rules continue to apply unchanged. A raw call can share an endpoint with several SDK functions and matches all of them; a function name never grants permission or bypasses existing restrictions.

For example, this rule requires approval before an agent creates a Jira issue:

{
"effect": "require_approval",
"when": { "operation": "atlassian.createissue" },
"approval": { "approvers": ["reviewer@example.com"] }
}

Save it with alter policy rules create --app <app-id> --grant <grant-id> --type require_approval --body @rule.json, or select the function in the portal.

Report an issue with this page

Necessary

Required for sign-in, security, authorization, and remembering your choices.

Always active

Analytics

Helps us understand which product and documentation features are useful.

Performance diagnostics

Uses performance tracing and privacy-masked session replay to diagnose problems.

You can change these choices at any time from Cookie settings.