Overview

There are three ways to interact with the Jira API through our platform:

Jira API Quirks

Every Jira REST API request requires a project name to be associated with it (this helps identify the project you want to register the webhook for). Because of this, you will need to display a dropdown menu to your users so they can choose. We provide a hook that helps you display this data easily. See the example below on how to use it.

Creating a Webhook for a User

  1. Display list of the user projects using useGetJiraProjects: Using this hook, you can easily get a typed list of the current users projects.

    create-GitHub.ts
    import { useGetJiraProjects } from 'syncd-hooks';
    ...
    // Note: this is not async
    const { data, isLoading, error } = useGetJiraProjects({
     accessToken,
    });
    ...
     <select
     name="org"
     id="org"
     >
       {isLoading && <option value="loading">Loading...</option>}
       <option value="default">Select an organization</option>
       {data?.map((org) => (
         <option key={org.id} value={org.login}>
           {org.login}
         </option>
       ))}
    </select>
    ...
    
  2. Create a webhook using all the information you gatherd in the previous steps:

create-Jira.ts
/**
 * We use JSDocs in the SDK to give you the best experience possible.
 * If you need to know what a function does, you can hover over it in your IDE.
 * If you need to know why you need a projectId for example, you can hover over it.
 */
const res = await syncdClient.providers.jira.webhooks.create({
  accessToken: "<access-token>",
  callbackUrl: "<callback-url>",
  events: ["jira:issue_created"],
  jiraProjectName: "TP",
  endpointName: "Jira Test",
  projectId: "<your-project-id>",
  endpoindDescription: "This is a test endpoint",
  externalUser: {
    uniqueId: "user_a2l0Y2hlbGxvsdf23sd2sdf2",
    firstName: "Thomas",
    lastName: "Cistulli",
    metadata: {
      email: "test@test.com",
    },
  },
});

Updating a Webhook for a User

If you don’t want to create a new webhook, you can update an existing one. This is useful if you want to change the callbackUrl or eventType. The resulting webhook will be under the same project and endpointId so you don’t need to worry about updating things in your database/storage.

Here is how that would look:

await syncdClient.providers.jira.webhooks.update({
  ...
})

Example Payloads

With each provider we have example payloads so you can test the webhook events. This can be useful for debugging and testing your application.

To import, each payload example starts with the provider name and then the event name. For example, figmaFileCommentEventExamplePayload. Use intelligent auto-complete in your IDE to find the payload you need.

Here’s an example of the Jira Issue Created Example Payload (you can import as jiraIssueCreatedExamplePayload):

  {
  rest: {
    issue: {
      id: "10104",
      self: "https://mycoolcompany.atlassian.net/rest/api/2/10104",
      key: "TP-105",
      fields: {
        statuscategorychangedate: "2024-07-13T17:04:53.945-0400",
        issuetype: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/issuetype/10001",
          id: "10001",
          description: "Tasks track small, distinct pieces of work.",
          iconUrl:
            "https://mycoolcompany.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10318?size=medium",
          name: "Task",
          subtask: false,
          avatarId: 10318,
          entityId: "6f3c8dc4-300a-4981-846c-e45f9e106c94",
          hierarchyLevel: 0,
        },
        timespent: null,
        customfield_10030: null,
        project: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/project/10000",
          id: "10000",
          key: "TP",
          name: "Test Project",
          projectTypeKey: "software",
          simplified: true,
          avatarUrls: {
            "48x48":
              "https://mycoolcompany.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10406",
            "24x24":
              "https://mycoolcompany.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10406?size=small",
            "16x16":
              "https://mycoolcompany.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10406?size=xsmall",
            "32x32":
              "https://mycoolcompany.atlassian.net/rest/api/2/universal_avatar/view/type/project/avatar/10406?size=medium",
          },
        },
        customfield_10031: null,
        fixVersions: [],
        aggregatetimespent: null,
        customfield_10035: null,
        resolution: null,
        customfield_10036: null,
        customfield_10037: null,
        customfield_10027: null,
        customfield_10028: null,
        customfield_10029: null,
        resolutiondate: null,
        workratio: -1,
        watches: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/issue/TP-105/watchers",
          watchCount: 0,
          isWatching: true,
        },
        lastViewed: null,
        issuerestriction: {
          issuerestrictions: {},
          shouldDisplay: true,
        },
        created: "2024-07-13T17:04:53.599-0400",
        customfield_10020: null,
        customfield_10021: null,
        customfield_10022: null,
        customfield_10023: null,
        priority: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/priority/3",
          iconUrl:
            "https://mycoolcompany.atlassian.net/images/icons/priorities/medium.svg",
          name: "Medium",
          id: "3",
        },
        customfield_10024: null,
        customfield_10025: null,
        labels: [],
        customfield_10016: null,
        customfield_10017: null,
        customfield_10018: {
          hasEpicLinkFieldDependency: false,
          showField: false,
          nonEditableReason: {
            reason: "PLUGIN_LICENSE_ERROR",
            message: "The Parent Link is only available to Jira Premium users.",
          },
        },
        customfield_10019: "0|i000mn:",
        timeestimate: null,
        aggregatetimeoriginalestimate: null,
        versions: [],
        issuelinks: [],
        assignee: null,
        updated: "2024-07-13T17:04:53.599-0400",
        status: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/status/10000",
          description: "",
          iconUrl: "https://mycoolcompany.atlassian.net/",
          name: "To Do",
          id: "10000",
          statusCategory: {
            self: "https://mycoolcompany.atlassian.net/rest/api/2/statuscategory/2",
            id: 2,
            key: "new",
            colorName: "blue-gray",
            name: "New",
          },
        },
        components: [],
        timeoriginalestimate: null,
        description: null,
        customfield_10010: null,
        customfield_10014: null,
        timetracking: {},
        customfield_10015: null,
        customfield_10005: null,
        customfield_10006: null,
        customfield_10007: null,
        security: null,
        customfield_10008: null,
        aggregatetimeestimate: null,
        attachment: [],
        customfield_10009: null,
        summary: "Testing",
        creator: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/user?accountId=slkfjlk2j34234234234lkjfds",
          accountId: "slkfjlk2j34234234234lkjfds",
          avatarUrls: {
            "48x48":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
            "24x24":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
            "16x16":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
            "32x32":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
          },
          displayName: "John Doe",
          active: true,
          timeZone: "America/New_York",
          accountType: "atlassian",
        },
        subtasks: [],
        reporter: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/user?accountId=slkfjlk2j34234234234lkjfds",
          accountId: "slkfjlk2j34234234234lkjfds",
          avatarUrls: {
            "48x48":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
            "24x24":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
            "16x16":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
            "32x32":
              "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
          },
          displayName: "John Doe",
          active: true,
          timeZone: "America/New_York",
          accountType: "atlassian",
        },
        aggregateprogress: {
          progress: 0,
          total: 0,
        },
        customfield_10001: null,
        customfield_10002: [],
        customfield_10003: null,
        customfield_10004: null,
        environment: null,
        duedate: null,
        progress: {
          progress: 0,
          total: 0,
        },
        votes: {
          self: "https://mycoolcompany.atlassian.net/rest/api/2/issue/TP-105/votes",
          votes: 0,
          hasVoted: false,
        },
      },
    },
    issue_event_type_name: "issue_created",
    changelog: {
      id: "10172",
      items: [
        {
          field: "priority",
          fieldtype: "jira",
          fieldId: "priority",
          from: null,
          fromString: null,
          to: "3",
          toString: "Medium",
        },
        {
          field: "reporter",
          fieldtype: "jira",
          fieldId: "reporter",
          from: null,
          fromString: null,
          to: "slkfjlk2j34234234234lkjfds",
          toString: "John Doe",
          tmpFromAccountId: null,
          tmpToAccountId: "slkfjlk2j34234234234lkjfds",
        },
        {
          field: "Status",
          fieldtype: "jira",
          fieldId: "status",
          from: null,
          fromString: null,
          to: "10000",
          toString: "To Do",
        },
        {
          field: "summary",
          fieldtype: "jira",
          fieldId: "summary",
          from: null,
          fromString: null,
          to: null,
          toString: "Testing",
        },
      ],
    },
    user: {
      self: "https://mycoolcompany.atlassian.net/rest/api/2/user?accountId=slkfjlk2j34234234234lkjfds",
      accountId: "slkfjlk2j34234234234lkjfds",
      avatarUrls: {
        "48x48":
          "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
        "24x24":
          "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
        "16x16":
          "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
        "32x32":
          "https://secure.gravatar.com/avatar/e7f7fbc33449e9590eee7accad57efe9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FTC-6.png",
      },
      displayName: "John Doe",
      active: true,
      timeZone: "America/New_York",
      accountType: "atlassian",
    },
    matchedWebhookIds: [109],
    timestamp: 1720904693790,
  },
  webhookEvent: "jira:issue_created",
};

Types

We also provide types for all supported event payloads. This can be helpful when you are consuming webhooks on your endpoint. Instead of the payload body being an any type, now you can do something like this:

import { TJiraIssueCreated } from '@syncd-sdk';
...
// Now the body is fully typed
const body: TJiraIssueCreated = await req.json();
...

Zod Schemas - Coming Soon

This will allow you to validate the incoming webhook body against a schema. This can be useful for ensuring the body is correct before processing it.

Internal company webhooks

If you want to use Syncd as an internal webhook sending, regestration, and managment service, the dashboard has you covered. We handle and mange the access tokens with one click.