Last updated Jan 8, 2025

JIRA Developer Documentation : JIRA JSON-RPC Overview

This page has been archived, as it does not apply to the latest version of JIRA (Server or Cloud). The functionality described on this page may be unsupported or may not be present in JIRA at all.

JIRA's SOAP and XML-RPC remote APIs were removed in JIRA 7.0 for Server ( see announcement). We encourage you to use JIRA's REST APIs to interact with JIRA remotely (see migration guide).

Why JSON-RPC

The future of remote APIs in JIRA lies with REST. However, until these APIs are fully built out, up to now the only option was to use the SOAP APIs.

SOAP messaging is unfriendly to many developers, especially those wanting to make calls to JIRA in a browser AJAX environment.

For this reason, we have added the JSON-RPC capability to enable a transition from the current SOAP APIs to a more JSON/JavaScript friendly mechanism.

The code uses the Java server code that makes up the existing SOAP interface in JIRA. There is a one-to-one mapping between the methods and parameters in the JIRA SOAP API and the equivalent JSON-RPC methods and parameters.

The main difference is the JSON-RPC wire format.

How the API is Implemented

The JSON-RPC API is provided by an open source plugin that is bundled with JIRA 4.4 and later. You can find it here on BitBucket.

The plugin uses the code that provides SOAP methods and converts them to JSON-RPC methods. It uses Jackson as the JSON library to provide the mapping between a Java method and JSON-RPC invocation of that method.

The code was originally written as a Confluence plugin and then ported to a JIRA plugin. The mechanism works in both products in very similar manner.

The SOAP calls are made as a POST on the following path:

http://host:port/jira/rpc/soap/jirasoapservice-v2

The JSON-RPC calls are made as POST on this path:

http://host:port/jira/rpc/json-rpc/jirasoapservice-v2

Responses are delivered as MIME type application/json. Your requests should be too, but that is not enforced by the plugin.

Getting Started

As mentioned above, there is a one-for-one mapping between a SOAP method call and a JSON-RPC method call. For example, the Javadoc for the JIRA SOAP API shows this getServerInfo() method.

1
2
RemoteServerInfo getServerInfo(java.lang.String token)

where RemoteServerInfo is defined as this:

1
2
public RemoteServerInfo {

   java.lang.String getBaseUrl()

   java.util.Date getBuildDate()


   java.lang.String getBuildNumber() ;

   RemoteTimeInfo getServerTime() ;

   java.lang.String getVersion()
}

To make the same call via JSON-RPC, you need to fire the following POST request onto http://hostname:80/jira/rpc/json-rpc/jirasoapservice-v2:

1
2
REQUEST :
{
    "jsonrpc" : "2.0",
    "method" :
    "getServerInfo",
    "params" :  ["l632EGg4Kc"],
    "id" : 12345
}

RESPONSE :
{
   "id":12345,
   "result": {
      "version":"4.4-SNAPSHOT",
      "buildNumber":"634",
      "baseUrl":"http://localhost:8090/jira",
      "buildDate":1303135200000,
      "serverTime":{
         "timeZoneId":"Australia/Sydney",
         "serverTime":"2011-04-19T12:36:11.540+1000"}
        }
      },
    "jsonrpc":"2.0"
}

Let's have a look at the structure of the JSON-RPC message. It follows the JSON-RPC specification format.

Property

Comments

jsonrpc

Required. Must have the value "2.0".

method

Specifies the method to call.

params

An array of parameters to be passed to the method. In this case the string "l632EGg4Kc" is a security token which we will discuss later.

id

A unique request ID of your choosing. It will be echoed back to you so that you can marry requests with response. This is particularly useful if you use an asynchronous fire and forget programming technique.

The response contains the echoed request "id" property and a "result" property that is a JSON object mapping of the RemoteServerInfo object. It maps the public methods of the object into JSON properties.

You must use the HTTP POST verb. You cannot use GET to invoke JSON-RPC methods.

The Light Protocol

The plugin also supports a 'light' protocol that allows clients to encode the method name in the URL, and provide only the method arguments in the request body. Non-error responses in the light protocol also omit the RPC envelope and only provide what would normally be the 'result' object in a regular JSON-RPC response.

Error responses are returned as they would under the heavy protocol.

Thus the equivalent to the above request in the light protocol would be as follows.

Remember the method name now goes into the URL and not the POST body.

1
2
http://hostname:80/jira/rpc/json-rpc/jirasoapservice-v2/getServerInfo

The POST data is:

1
2

REQUEST :

["l632EGg4Kc"]

RESPONSE :

{
    "baseUrl": "http://jira.atlassian.com",
    "buildDate": 1314680400000,
    "buildNumber": "660",
    "serverTime": {
        "serverTime": "2011-09-22T17:52:05.751-0500",
        "timeZoneId": "US/Central"
    },
    "version": "4.4.1"
}

It's up to you whether you want to use the full or the light JSON-RPC format.

One advantage of the light format is that access logs will contain the method invoked because it is in the URL. The heavy format will not, because the method is inside the POST data.

Date Conversion

Because JSON has no native date type, dates are represented in JSON as the number of milliseconds since the epoch, GMT. In JavaScript you can pass this number into the Date() constructor to get a Date object, and you can get it back out by calling Date.getTime().

Authentication

You must authenticate with JIRA in order to make SOAP or JSON-RPC API calls. There is a login method that takes a username and password:

1
2
java.lang.String login(java.lang.String username, java.lang.String password) throws RemoteException,RemoteAuthenticationException

which maps to a JSON-RPC message as follows:

1
2
{
    "jsonrpc" : "2.0",
    "method" : "login",
    "params" : ["username","password"],
    "id" : 12345
}

This will return an authentication token string that you provide to every other subsequent method call:

1
2
{
    "id": 12345,
    "jsonrpc": "2.0",
    "result": "l632EGg4Kc"
}

If the password is incorrect then you will get a JSON-RPC error message back:

1
2
{
    "error": {
        "code": 500,
        "data": "com.atlassian.jira.rpc.exception.RemoteAuthenticationException: Invalid username or password.\n...\tat java.lang.Thread.run(Thread.java:662)\n",
        "message": "The application was unable to serve your request: com.atlassian.jira.rpc.exception.RemoteAuthenticationException: Invalid username or password."
    },
    "id": 12345,
    "jsonrpc": "2.0"
}

In reality, the data portion of the above example is a full Java stack trace (which like all stack traces is pretty long) and hence in this example I have cut it down using the ... characters.

The same sort of error will occur if the token expires:

1
2
{
    "error": {
        "code": 500,
        "data": "com.atlassian.jira.rpc.exception.RemoteAuthenticationException: User not authenticated yet, or session timed out....\n\tat java.lang.Thread.run(Thread.java:662)\n",
        "message": "The application was unable to serve your request: com.atlassian.jira.rpc.exception.RemoteAuthenticationException: User not authenticated yet, or session timed out."
    },
    "id": 12345,
    "jsonrpc": "2.0"
}

There is a logout method which will invalidate the authorisation token and hence prevent it being used for further method calls.

Authentication via another Mechanism

If you have established a JIRA session by some other means (for example you are running in the browser and the user has already logged in) then the token parameter is not checked.

It is still required in the method signature but it will not be validated and hence it can be any value. Remember that browsers keep the user's JIRA session by propagating the JSESSIONID cookie that JIRA sets.

Command line scripts via wget or curl, for example, do not typically keep the user's session. You will need to propagate JSESSIONID if you want to use an alternative authentication mechanism.

More Examples

getProjectByKey()

1
2
REQUEST:
{
    "jsonrpc" : "2.0",
    "method" :
    "getProjectByKey",
    "params" :  ["Mw7ehWPnKg", "JRA" ],
    "id" : 12345
}

RESPONSE:
{
    "id": 12345,
    "jsonrpc": "2.0",
    "result": {
        "description": "",
        "id": "10240",
        "issueSecurityScheme": null,
        "key": "JRA",
        "lead": "pslade@atlassian.com",
        "name": "JIRA",
        "notificationScheme": null,
        "permissionScheme": null,
        "projectUrl": "http://www.atlassian.com/software/jira",
        "url": "http://jira.atlassian.com/browse/JRA"
    }
}

getIssue()

1
2
REQUEST:
{
    "jsonrpc" : "2.0",
    "method" :
    "getIssue",
    "params" :  ["Mw7ehWPnKg", "JRA-666"],
    "id" : 12345
}

RESPONSE:

{
    "id": 12345,
    "jsonrpc": "2.0",
    "result": {
        "affectsVersions": [],
        "assignee": "mike@atlassian.com",
        "attachmentNames": [],
        "components": [
            {
                "id": "10121",
                "name": "Backend / Domain Model"
            }
        ],
        "created": 1029379347880,
        "customFieldValues": [
            {
                "customfieldId": "customfield_11130",
                "key": null,
                "values": [
                    "43020"
                ]
            },
            {
                "customfieldId": "customfield_10160",
                "key": null,
                "values": [
                    "2937600"
                ]
            },
            {
                "customfieldId": "customfield_10161",
                "key": null,
                "values": [
                    "true"
                ]
            },
            {
                "customfieldId": "customfield_10150",
                "key": null,
                "values": [
                    "bbaker",
                    "mike@atlassian.com"
                ]
            },
            {
                "customfieldId": "customfield_10301",
                "key": null,
                "values": [
                    "<div class=\"notify info\" style=\"margin-bottom: 10px;\">\r\n<b>PLEASE NOTE:</b>\r\n<p>\r\nTest issues should be created in the <a href=\"http://jira.atlassian.com/secure/CreateIssue.jspa?pid=10420&issuetype=2\">Test Project</a>.\r\n</div>"
                ]
            }
        ],
        "description": "Like JRA-662 for resolutions!",
        "duedate": null,
        "environment": null,
        "fixVersions": [
            {
                "archived": true,
                "id": "10280",
                "name": "1.4",
                "releaseDate": 1031634000000,
                "released": true,
                "sequence": 28
            }
        ],
        "id": "11473",
        "key": "JRA-666",
        "priority": null,
        "project": "JRA",
        "reporter": "mike@atlassian.com",
        "resolution": "1",
        "status": "6",
        "summary": "Ability to set custom resolutions",
        "type": "2",
        "updated": 1313718224836,
        "votes": 0
    }
}

getActionsForIssues()

1
2
REQUEST:
{
    "error": {
        "code": -32601,
        "data": null,
        "message": "RPC method not found: getActionsForIssue"
    },
    "id": 12345,
    "jsonrpc": "2.0"
}

RESPONSE:

{
    "id": 12345,
    "jsonrpc": "2.0",
    "result": [
        {
            "id": "61",
            "name": "Reopen"
        }
    ]
}

getIssueTypes()

1
2
REQUEST :
{
    "jsonrpc" : "2.0",
    "method" :
    "getIssueTypes",
    "params" :  ["Mw7ehWPnKg"],
    "id" : 12345
}

RESPONSE :

{
    "id": 12345,
    "jsonrpc": "2.0",
    "result": [
        {
            "description": "",
            "icon": "http://jira.atlassian.com/images/icons/bug.gif",
            "id": "10",
            "name": "Atlassian Task",
            "subTask": false
        },
        {
            "description": "A problem which impairs or prevents the functions of the product.",
            "icon": "http://jira.atlassian.com/images/icons/bug.gif",
            "id": "1",
            "name": "Bug",
            "subTask": false
        },
        ...
        {
            "description": "An issue relating to a third-party product (eg. app server) that nevertheless affects this product",
            "icon": "http://jira.atlassian.com/images/icons/genericissue.gif",
            "id": "7",
            "name": "Third-party issue",
            "subTask": false
        },
        {
            "description": "A story that's more about making a feature most lust worthy",
            "icon": "http://jira.atlassian.com/images/icons/health.gif",
            "id": "23",
            "name": "UX Story",
            "subTask": false
        }
    ]
}

Methods Available

The methods available to the JSON-RPC API are all the methods defined in the JIRA SOAP API Javadoc.

You must translate from the Java structure into JSON objects. Use the normal JavaBean rules for translating from one into the other.

Rate this page: