Skip to content

Jira#

Jira (Cloud) is the second provider adapter. It imports Jira issues and their referenced users into TeamBoost, from either a CSV export or the Jira REST API, and projects each issue into a TeamBoost task-create draft for review.

Capability Method Status
CSV_IMPORT Upload a Jira issue CSV export ✅ Built
SYNC Pull issues from the Jira REST API ✅ Built
WEBHOOK Not built (see Roadmap)

The endpoints below live under /api/v1/providers/jira/.... They are generic — the same routes serve any registered provider by substituting the {provider} path segment — but the request/response shapes shown here are exactly what Jira returns today. All routes require an organization-scoped user token (see Authentication).

Credentials (for API sync)#

Unlike Linear's single key, Jira Cloud uses HTTP Basic auth over an API token, so the stored credential is a small JSON object — { "site", "email", "token" } — encrypted at rest and never returned by any endpoint. CSV import needs no credential.

Create an API token at Atlassian account → Security → Create and manage API tokens → Create API token; site is your <your-org>.atlassian.net host and email is the Atlassian account the token belongs to.

PUT /api/v1/providers/jira/credentials?organization_id=<id>
curl -X PUT "https://<host>/api/v1/providers/jira/credentials?organization_id=590789" \
  -H "Authorization: Bearer <user-token>" \
  -H "Content-Type: application/json" \
  -d '{ "secret": "{\"site\":\"your-org.atlassian.net\",\"email\":\"you@org.com\",\"token\":\"<api-token>\"}" }'

POST /api/v1/providers/jira/credentials/verify live-tests the credential with a cheap /myself probe; DELETE removes it.

Importing#

Both entry points produce the same reviewable import session. Each parsed issue is projected into a TeamBoost advanced task-create draft at import time, so the session is reviewable as proposed TeamBoost work. Nothing is written to TeamBoost yet — the session is for review, mapping, and confirmation.

From a CSV export#

Produce the file in Jira at Issues → (filter/search) → Export → Export CSV (all fields). The export quirks the adapter handles: repeated headers for multi-value fields (e.g. Labels), display-name-only actors with stable ids in the separate Assignee Id / Reporter Id / Creator Id columns, and locale-style dd/MMM/yy h:mm a timestamps (no timezone marker — assumed UTC).

POST /api/v1/providers/jira/imports/csv?organization_id=<id>
curl -X POST "https://<host>/api/v1/providers/jira/imports/csv?organization_id=590789" \
  -H "Authorization: Bearer <user-token>" \
  -F "file=@jira_export.csv"

From the API (sync)#

POST /api/v1/providers/jira/imports/sync?organization_id=<id>

Uses the stored credential to pull issues (token-cursor pagination) and their referenced users.

The import session#

{
  "status": "success",
  "message": "CSV parsed; review the proposed user mapping.",
  "data": {
    "id": "a1b2c3…",
    "provider": "jira",
    "capability": "CSV_IMPORT",
    "filename": "jira_export.csv",
    "status": "PENDING_REVIEW",
    "summary": { "taskCount": 6, "userCount": 1, "errorCount": 0,
                 "projectionErrorCount": 0, "mappingNoteCount": 3 },
    "taskEntries": [ {
      "index": 0,
      "source": { "summary": "sam", "issue_key": "SCRUM-6", "issue_id": "10005",
                  "issue_type": "Task", "status": "To Do", "project_name": "Yoterra",
                  "sprint": "SCRUM Sprint 0", "project_lead": "Aziz Khelifi", "...": "…" },
      "normalized": { "identifier": "SCRUM-6", "title": "sam", "status": "TODO",
                      "assigneeAccountId": "62eede…", "createdAt": "…" },
      "projected": {
        "title": "sam", "type": "OTHER", "status": "NOT_STARTED", "priority": "MEDIUM",
        "ownerId": 590782, "projectTitle": "Yoterra", "source": "jira",
        "scheduleStage": "PENDING", "previousDependencies": [],
        "descriptionJson": { "provider": "jira", "issueKey": "SCRUM-6", "issueId": "10005",
                             "issueType": "Task", "project": "Yoterra", "sprint": "SCRUM Sprint 0" }
      },
      "projectionErrors": [],
      "mappingNotes": [],
      "metadata": { "provider": "jira", "providerId": "10005", "identifier": "SCRUM-6",
                    "parentIdentifier": null }
    } ],
    "userMappings": [ { "sourceAccountId": "62eede…", "sourceName": "Aziz Khelifi",
                        "matchedUserId": 590782, "method": "NAME_SIMILARITY", "confidence": 0.9 } ],
    "rowErrors": []
  }
}

Each parsed issue becomes a task entry: the normalized source, a projected TeamBoost task-create draft (pass-through ready for the advanced task-create API), blocking projectionErrors, and non-blocking mappingNotes.

What gets projected#

Jira source TeamBoost draft field
Summary title (min length 2; shorter → projection error)
Issue Type typeBugBUG, Feature/StoryNEW_FEATURE, others→OTHER (note on unknowns)
Status Category status — To Do→NOT_STARTED, In Progress→IN_PROGRESS, Done→COMPLETED
Priority priorityURGENT/HIGH/MEDIUM/LOW, else UNKNOWN
Assignee (by account id → user mapping) ownerId
Reporter (by account id → user mapping) requestedById
Labels / Project name labels / projectTitle (names — TeamBoost maps/creates them)
Due date plannedEndDate
Parent key descriptionJson.parentKey (preserved as context, not a dependency)
Provider refs + raw-only columns descriptionJson (issueKey, issueId, issueType, raw status/priority, project, parentKey, dueDate; plus sprint/resolution on CSV imports only — API sync omits these until the API mapping surfaces them)

A subtask keeps its parent key in descriptionJson (parent/subtask links are not turned into dependencies), and an assignee resolves to ownerId through the user mapping — so SCRUM-6 above shows its owner. Jira's Created timestamp is not mapped to a scheduling date; the full provider record is preserved losslessly on the entry's source.

Mapping notes vs projection errors#

  • mappingNotes flag provisional or ambiguous choices for review (an unknown issue type, Reporter-vs-Creator). They never block confirmation.
  • projectionErrors are blocking: a too-short title, or an assignee present on the issue but not mapped to a TeamBoost member. Any entry with an error puts the session in PROJECTION_ERRORS.

Reviewing, editing, confirming#

Route Purpose
GET /api/v1/providers/jira/imports/{id} Fetch the session for review.
PATCH /api/v1/providers/jira/imports/{id}/mappings Replace the user mapping; the session re-projects (mapping a previously unmapped assignee clears its owner error). Set confirm: true to confirm.
PATCH /api/v1/providers/jira/imports/{id}/task-entries/{index} Replace one entry's projected draft by its 0-based index.

Confirming is rejected with 409 projection_errors_remain while any entry still has a projectionError; mapping notes alone do not block. The execute step that pushes a confirmed session into TeamBoost is not built yet (see Roadmap).

Normalized vocabularies#

Jira values are mapped onto TeamBoost-neutral enums during parse, then onto the TeamBoost task-create vocabularies during projection:

  • Task status (status): BACKLOG, TODO, IN_PROGRESS, DONE, CANCELED, UNKNOWN. Jira's Status Category drives this (the per-workflow status name is customisable); an unrecognized category maps to UNKNOWN.
  • Priority (priority): NONE, URGENT, HIGH, MEDIUM, LOW, UNKNOWN.

User mapping#

Jira CSV exports carry no e-mail — users are a display name plus a stable accountId. Matching against your TeamBoost member directory therefore leans on name similarity (and the e-mail local part when the API exposes an address). Each issue's assignee/reporter/creator account ids ride on the task so the projector can resolve owner and requester to TeamBoost user ids.