DEV Community

Cover image for From Specs to Tickets: Automating Jira Setup with Node.js and the Jira API
Constanza Diaz
Constanza Diaz

Posted on

From Specs to Tickets: Automating Jira Setup with Node.js and the Jira API

The plan was simple

Take the specs we'd written, turn them into Jira epics, stories and subtasks, and start sprinting.

It took longer than expected. Here's what actually happened — and what I learned.


Why automate Jira setup at all?

HandyFEM has 8 epics, 37 stories and ~160 subtasks. Creating that manually would take a full day and be error-prone. More importantly: the specs were already written in a structured format. Translating structured data into Jira issues is exactly the kind of repetitive task that should be automated.

So I wrote a Node.js script to do it via the Jira REST API.


Problem 1 — Jira Spaces ≠ Jira Classic

My account uses Jira Spaces — Atlassian's newer interface. The classic Jira has CSV import built in. Jira Spaces doesn't.

This isn't documented anywhere obviously. You discover it by looking for the import option and not finding it.

Lesson: always check which version of Jira you have before planning your workflow. The API still works, but some endpoints behave differently.


Problem 2 — The API token wasn't the issue (until it was)

First attempt: connection error. I assumed it was the token. It wasn't — it was an expired token from a previous session. Regenerating it fixed the connection.

The real lesson: curl -u email:token https://your-domain.atlassian.net/rest/api/3/myself is the fastest way to verify auth before running any script.


Problem 3 — customfield_10014 doesn't exist in team-managed projects

In classic Jira, linking a story to an epic uses a field called customfield_10014 (Epic Link). In team-managed projects (Jira Spaces), this field doesn't exist. You use parent instead.

The error was clear once I saw it:

"customfield_10014": "Field cannot be set. It is not on the appropriate screen, or unknown."
Enter fullscreen mode Exit fullscreen mode

Fix: remove customfield_10014, keep only parent: { id: epicId }.


Problem 4 — Board search doesn't work for team-managed projects

The Agile API endpoint /rest/agile/1.0/board?projectKeyOrId=HFM returns empty for team-managed projects, even when the board exists.

Claude Code caught this one after the first failure — it explained the root cause and the fix: hardcode the board ID directly instead of searching for it.

// This doesn't work for team-managed projects:
const boards = await fetch(`/rest/agile/1.0/board?projectKeyOrId=HFM`)

// This does:
const board = { id: 1, name: "SCRUM board" }
Enter fullscreen mode Exit fullscreen mode

What the final setup looks like

8 epics covering the full project lifecycle:

  • Planning & architecture (done)
  • Design System (in progress)
  • MVP screens (in progress)
  • Backend / Supabase
  • Security & privacy
  • PWA + SEO + emails
  • Testing & launch
  • AI Agentic features (v2)

37 stories with detailed descriptions and acceptance criteria.

~160 subtasks per story — including one for writing the blog post before closing the story. That last one matters: documentation that lives next to the work gets written. Documentation planned separately doesn't.

8 sprints mapped to the logical build order — from DS implementation to public launch in Barcelona.


Security: never hardcode tokens

The scripts use node --env-file=.env.local (native in Node v18+) to load credentials. No dotenv dependency, no token in the codebase.

node --env-file=.env.local docs/handyfem-jira-import.js
Enter fullscreen mode Exit fullscreen mode

Both scripts are in .gitignore. Claude Code was instructed to never write sensitive values directly — always give instructions for the developer to add them manually.


What I'd do differently

Start with a simple API test before writing the full script. One curl call to verify auth and one to verify the project endpoint would have saved 30 minutes of debugging, and a lot of Claude tokens.

Also: when automating Jira, always check whether your project is classic or team-managed first. The API surface is different enough to matter.


The scripts

Both scripts are in docs/ in the HandyFEM repo:

  • handyfem-jira-import.js — creates epics, stories and subtasks
  • handyfem-jira-sprints.js — creates sprints and assigns issues

📚 HandyFEM App Series
🔗 Previous: Building HandyFEM's Design System with Claude.ai
🔗 Next: Coming soon — Building the Design System in Code with Claude Code
🏷️ All posts in this series: #HandyFEMApp

Building in public. All mistakes included.

Top comments (0)