Forming calls with GraphQL

Learn how to authenticate to the GraphQL API, then learn how to create and run queries and mutations.

Authenticating with GraphQL

To communicate with the GraphQL server, you'll need a user token.

Follow the steps in "Creating a personal access token" to create a token. The token is linked to your user account.

The GraphQL endpoint

The REST API has numerous endpoints; the GraphQL API has a single endpoint:


The endpoint remains constant no matter what operation you perform.

Communicating with GraphQL

Because GraphQL operations consist of multiline JSON, Sirius recommends using the Explorer available at the GraphQL endpoint to make GraphQL calls. You can also use cURL or any other HTTP-speaking library.

In REST, HTTP verbs determine the operation performed. In GraphQL, you'll provide a JSON-encoded body whether you're performing a query or a mutation, so the HTTP verb is POST.

To query GraphQL using cURL, make a POST request with a JSON payload. The payload must contain a string called query:

curl -H "Authorization: bearer token" -X POST -d " \\
{ \\
\\"query\\": \\"query { user { email }}\\" \\
} \\
" https://*

Note: The string value of "query" must escape newline characters or the schema will not parse it correctly. For the POST body, use outer double quotes and escaped inner double quotes.

About query and mutation operations

The two types of allowed operations in GraphQL API are queries and mutations. Comparing GraphQL to REST, queries operate like GET requests, while mutations operate like POST/PATCH/DELETE. The mutation name determines which modification is executed. For information about rate limiting, see "Rate limiting." Queries and mutations share similar forms, with some important differences.

About queries

GraphQL queries return only the data you specify. To form a query, you must specify fields within fields (also known as nested subfields) until you return only scalars.

Queries are structured like this:

query { JSON objects to return }

For a real-world example, see "Example query."

About mutations

To form a mutation, you must specify three things:

  1. Mutation name. The type of modification you want to perform.
  2. Input object. The data you want to send to the server, composed of input fields. Pass it as an argument to the mutation name.
  3. Payload object. The data you want to return from the server, composed of return fields. Pass it as the body of the mutation name. Mutations are structured like this:
mutation {
mutationName(input: {MutationNameInput!}) {

The input object in this example is MutationNameInput, and the payload object is MutationNamePayload. In the mutations reference, the listed input fields are what you pass as the input object. The listed return fields are what you pass as the payload object. For a real-world example, see "Example mutation."

Working with variables

Variables can make queries more dynamic and powerful, and they can reduce complexity when passing mutation input objects.

Note: If you're using the Explorer, make sure to enter variables in the separate query variables pane, and do not include the word variables before the JSON object.

Example query

Let's walk through a more complex query and put this information in context.

The following query looks up the logged in user email:

query {
user {

Looking at the composition line by line:

  • query { Because we want to read data from the server, not modify it, query is the root operation. (If you don't specify an operation, query is also the default.)

  • user { To begin the query, we want to find the user object.

  • id We want the id field of the User object returns by user field, it is a Int scalar, so it is a leaf.

  • email

    We want the email field of the User object returns by user field, it is a String scalar, so it is a leaf.

Example mutation

Mutations often require information that you can only find out by performing a query first. This example shows two operations:

  1. A query to get an issue ID.
  2. A mutation to add an emoji reaction to the issue.
mutation ($liveId: Int!, $text: String!) {
createLiveContribution(input: { liveId: $liveId, text: $text }) {
contribution {

Looking at the composition line by line:

  • mutation($liveId: ID!, $text: String!) { Here we're performing a mutation. Two variables are specified: $liveId: ID! and $text: String!. The variables type should match the expected input type.
  • createLiveContribution(input: { liveId: $liveId, text: $text }) { Let's examine this line:
    • createLiveContribution is the name of the mutation.
    • input is the required argument key. This will always be input for a mutation.
    • { liveId: $liveId, text: $text } is the required argument value. This will always be an input object (hence the curly braces) composed of input fields (liveId and text in this case) for a mutation. How do we know which value to use for the liveId and the text? The createLiveContribution docs tell us the liveId field has the type ID! and the text has the type String!. The ! means that the value cannot be ommitted or null.
  • The rest of the call is composed of the payload object. This is where we specify the data we want the server to return after we've performed the mutation. These lines come from the createLiveContribution docs, which three possible return fields:
    • id (ID!)
    • contribution (Contribution!) In this example, we return the two required fields (id and contribution), contribution has required subfields (id and text). When we run the mutation, this is the response:
"data": {
"createLiveContribution": {
"id": "2399",
"contribution": {
"id": "1203",
"text": "HOORAY"

Rate limiting

A rate limit is the number of API calls user can make within a given time period. If this limit is exceeded requests will fail.

Use the HTTP headers in order to understand where the application is at for a given rate limit.

  • X-RateLimit-Limit: the rate limit ceiling (default: 10000)
  • X-RateLimit-Remaining: the number of requests left for the minute window
  • X-RateLimit-Reset: the remaining window before the rate limit resets, in seconds

When a user exceeds the rate limit, the API will return a HTTP 429 “Too Many Requests” response code

Further reading

There is a lot more you can do when forming GraphQL calls. Here are some places to look next:

Edit this page on GitHub