Mirror new Jira issues into Notion
Every issue Jira raises is mirrored as a page in a Notion database, for people who live in Notion.
Drag to pan, pinch to zoom. This is the real graph the template installs.
Purpose
Every issue Jira raises is mirrored as a page in a Notion database, for people who live in Notion.
How it works
What it does
- Subscribes to Jira's
jira:issue_created, narrowed with a JQL filter. - Creates a Notion page titled
KEY — summarywith status, priority and a link back.
Validation
This template is contract-validated: the unit suite checks every node type, every config key and the whole graph against the same rules a saved workflow passes. It has not been run against the live provider — the ids, names and columns below are placeholders to replace with your own.
Nodes 2
- 01Issue createdtrigger.jira_eventTrigger
- 02Mirror into Notionnotion.create_pageApp
View template JSON
{
"format": "mantle-workflow/v1",
"id": "notion-jira-bug-mirror",
"name": "Mirror new Jira issues into Notion",
"graph": {
"nodes": [
{
"id": "event",
"type": "trigger.jira_event",
"label": "Issue created",
"config": {
"events": [
"jira:issue_created"
],
"jql_filter": "project = ENG"
},
"worker_type": "generic-worker",
"position": {
"x": 60,
"y": 220
}
},
{
"id": "page",
"type": "notion.create_page",
"label": "Mirror into Notion",
"config": {
"database_id": "00000000000000000000000000000000",
"title": "{{ $json.issue.key }} — {{ $json.issue.summary }}",
"simple_properties": {
"Status": "{{ $json.issue.status }}",
"Priority": "{{ $json.issue.priority }}",
"Link": "{{ $json.issue.url }}"
},
"property_types": {
"Status": "select",
"Priority": "select",
"Link": "url"
}
},
"worker_type": "generic-worker",
"position": {
"x": 380,
"y": 220
}
}
],
"edges": [
{
"from": "event",
"to": "page"
}
]
}
}Requirements
The connections and permissions each step needs, from the node contracts in the catalog.
- JiraUsername & password
Used by Issue created.
Credential: {"email", "api_token"}
- Mantle creates the webhook in Jira when the workflow is published and deletes it when the workflow is unpublished, disabled or archived — do not add it by hand.
- The connection's account must be a Jira administrator: registering a webhook is an admin operation, and publish fails with Jira's own message if it is not.
- Deliveries are signed. Mantle generates a random secret, registers it, and verifies the X-Hub-Signature HMAC over the raw body; a bad signature is refused before any run starts.
- If your site does not confirm signing (no isSigned on registration) the webhook is deleted again and the publish fails, rather than leaving an unauthenticated URL armed. Tick allow_unsigned to accept URL-only authentication anyway — then anyone who learns the callback URL can start runs.
- jql_filter and events are applied when the workflow is published, so they cannot use {{ }} expressions — there is no run to evaluate them against.
- Jira sends no delivery id. Runs are deduped on webhookEvent + issue id + timestamp + the change-group / comment / worklog id, so a Jira retry cannot start a second run.
- MANTLE_APP_PUBLIC_BASE_URL must be a public https:// URL — Jira refuses to register a plain-http or unreachable callback.
- NotionAPI key
Used by Mirror into Notion.
Credential: the integration token, or {"token": "…"}
- Share the target database with your integration in Notion (••• → Connections) or the API returns 'Could not find database'.
Setup
- Set
jql_filterto your project; the webhook fires for everything the filter matches. - Set
database_id, and make sure the Notion database really hasStatus,PriorityandLinkproperties of the declared types. - Pick Jira and Notion connections.
Sample input and output
Synthetic examples: node-contract samples or placeholders, never customer data.
Input
What the Issue created trigger receives, as its node contract samples it.
{
"changelog": [],
"changelog_id": "",
"comment": {
"author": {
"accountId": "",
"displayName": "",
"emailAddress": ""
},
"body": "",
"created": "",
"id": "",
"updated": ""
},
"issue": {
"assignee": {
"accountId": "",
"displayName": "",
"emailAddress": ""
},
"id": "",
"issue_type": "",
"key": "ENG-412",
"labels": [],
"priority": "",
"project": {
"id": "",
"key": "ENG",
"name": ""
},
"reporter": {
"accountId": "",
"displayName": "",
"emailAddress": ""
},
"status": "",
"status_category": "",
"summary": "",
"url": ""
},
"issue_event_type_name": "issue_updated",
"payload": {},
"timestamp": 0,
"user": {
"accountId": "",
"displayName": "",
"emailAddress": ""
},
"webhookEvent": "jira:issue_updated",
"worklog": {
"author": {
"accountId": "",
"displayName": "",
"emailAddress": ""
},
"comment": "",
"id": "",
"started": "",
"time_spent": "",
"time_spent_seconds": 0
}
}Output
Mirror into Notion notion.create_page
{
"ok": true,
"page_id": "",
"url": ""
}Failure handling
What the graph does when a step fails, read from its retry settings, error branches and error policies.
- A step that fails, after any retries, fails the run. The failed step is kept with its input and error.
See it run, then make it yours.
Templates install as drafts. Edit any step, and Workflow Health re-checks the graph on every save.