External systems create work in Jira every day: support tools, monitoring alerts, intake forms, ERP events. On Jira Cloud, the clean way to accept those events inside an app you control is a Forge web trigger—an HTTPS endpoint that runs your function and can create issues through the Jira REST API.
This guide covers a production-minded path: authenticate callers, parse payloads, create issues with Atlassian Document Format (ADF), and ship without leaving public endpoints wide open.
When a web trigger is the right tool
Use a Forge web trigger when:
- A third-party system can POST JSON to a URL you control.
- You want the logic to live inside Atlassian’s Forge runtime (no separate VPS for the hot path).
- The action is “create or update a Jira issue” (or related Jira entities) with app-level permissions.
Prefer Forge remote/egress + your own API when the workflow needs heavy compute, long-running jobs, or secrets that should never sit next to Marketplace distribution constraints. For most “webhook in → issue out” flows, web triggers are enough.
Architecture at a glance
- Caller sends
POSTwith JSON body + auth header. - Web trigger function validates method, auth, and schema.
- Function maps fields → Jira project, issue type, summary, description (ADF), custom fields.
- Call
api.asApp().requestJira()with the right scopes. - Return a clear HTTP status and a correlation id the caller can log.
Manifest sketch
Declare a web trigger (prefer urlFormat: v2 for new apps), a function, and Jira scopes such as write:jira-work / read:jira-work as required by the endpoints you call. Keep the module key stable—rotating keys rotates URLs and breaks every caller.
modules:
webtrigger:
- key: intake-webhook
function: intake-handler
urlFormat: v2
function:
- key: intake-handler
handler: index.onIntake
permissions:
scopes:
- write:jira-work
- read:jira-work
Authenticate every request
Forge web trigger URLs are reachable on the public internet. Forge does not attach an Atlassian user for you. You must verify callers yourself.
- Shared secret: require
Authorization: Bearer <token>orX-HostHob-SignatureHMAC over the raw body. - Constant-time compare secrets; reject missing/invalid auth with
401before parsing business logic. - Store the secret in Forge environment variables / secrets—not in the repo.
- Optional allowlist: source IP ranges if the vendor publishes them (treat as defence in depth, not the only control).
Create the issue correctly
Jira Cloud’s create-issue API expects description in ADF for many projects. Build a minimal ADF doc from plain text, then expand when you need lists or links.
const description = {
type: 'doc',
version: 1,
content: [{
type: 'paragraph',
content: [{ type: 'text', text: payload.message || 'No message provided' }]
}]
};
const body = {
fields: {
project: { key: payload.projectKey },
issuetype: { name: 'Task' },
summary: payload.summary.slice(0, 255),
description
}
};
const res = await api.asApp().requestJira('/rest/api/3/issue', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
Validate projectKey and issue type against a config map. Never trust the caller to pick arbitrary projects in a multi-tenant Marketplace app—bind project selection to installation settings.
Idempotency and duplicates
Webhooks retry. Without idempotency you get duplicate issues.
- Accept an
idempotencyKey(or hash vendor event id + type). - Store processed keys in Forge storage with a TTL, or put the key in a custom field / entity property and search before create.
- Return the existing issue key when the event is a replay.
Production checklist
- Reject non-POST methods with
405. - Cap body size; fail fast on malformed JSON.
- Log correlation ids; never log full PII payloads.
- Map Jira API errors to actionable responses (
400validation vs502upstream). - Document the contract for the integrating team (fields, auth, example curl).
- Test with
forge tunnel, then a staging Jira site, then production install.
Common failure modes
- Missing scopes after adding endpoints—redeploy and re-consent.
- ADF validation errors—empty paragraphs or wrong node types.
- Permission schemes—app can authenticate but cannot create in that project.
- Secret rotation without dual-key window—callers fail until updated.
When to bring in an engineering partner
A hello-world trigger is an afternoon. A hardened intake path—multi-project routing, custom fields, attachment handling, retry queues, and Marketplace privacy review—is a product. If your team needs that path owned end to end, HostHob builds Forge apps and integrations as scoped delivery.
Need this built? HostHob ships production integrations and Marketplace-ready apps from Rotterdam. See our services or Talk to HostHob about your stack.
