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 | type — Bug→BUG, Feature/Story→NEW_FEATURE, others→OTHER (note on unknowns) |
| Status Category | status — To Do→NOT_STARTED, In Progress→IN_PROGRESS, Done→COMPLETED |
| Priority | priority — URGENT/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#
mappingNotesflag provisional or ambiguous choices for review (an unknown issue type, Reporter-vs-Creator). They never block confirmation.projectionErrorsare 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 inPROJECTION_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 toUNKNOWN. - 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.