Making API Calls

This guide demonstrates how to make API calls by putting together basic GraphQL ideas and Braintree-specific API details.

Since GraphQL requests can be made over HTTP, you can use curl to start testing the API from the command line. You can also use any HTTP library you prefer in your programming language of choice. The examples in this guide use curl.

The most basic query our API supports is ping. Here's the GraphQL query:

query {
  ping
}

And here's how you fit the above query into a well-formed HTTP request using curl:

curl \
 -H 'Content-Type: application/json' \
 -H 'Authorization: Basic PUBLICKEY:PRIVATEKEY_BASE64ENCODED' \
 -H 'Braintree-Version: 2019-01-01' \
 -X POST https://payments.sandbox.braintree-api.com/graphql \
 -d '{"query": "query { ping }", "variables": {} }'

This is what the response should look like:

{
  "data": {
    "ping": "pong"
  },
  "extensions": {
    "requestId": "a-uuid-for-the-request"
  }
}

The rest of this guide will go over each element in the above request and how to construct a more complex operation.

The Shape of a Request

To make any request to the Braintree GraphQL API, you make an HTTP request to

https://payments.sandbox.braintree-api.com/graphql

for the sandbox test environment, and

https://payments.braintree-api.com/graphql

for your live production account. The endpoint remains the same regardless of the operation you're performing.

We recommend a POST, although you can use a GET request.

Body

The request body should be JSON-formatted, with two keys: query and variables. The variables key can be optional depending on the request.

The value for query should be a single string consisting of a correctly formatted GraphQL query or mutation. This will specify what information you want to receive back in the Braintree API's response.

The value for variables should be the parameters that will be used in the request, in JSON format. For example, when charging a payment method, variables might consist of the ID for a PaymentMethod and the amount you wish to charge.

Here is a typical request body for the chargePaymentMethod mutation, formatted for readability:

{
  "query": "mutation chargePaymentMethod($input: ChargePaymentMethodInput!) {
      chargePaymentMethod(input: $input) {
        transaction {
          id
          status
        }
      }
    }
  ",
  "variables": {
    "input": {
      "paymentMethodId": "PAYMENT_METHOD_ID",
      "transaction": {
        "amount": "11.23"
      }
    }
  }
}

Note that the input key in the variables section maps to the $input variable defined by the mutation in the query section. You can name this key whatever you would like (see below for an example).

If the query you're using doesn't take a complex set of parameters, variables can be omitted.

Inline Variables

If the query or mutation does not take a complex input type with multiple fields, you have the option to inline the variables into the query field.

For instance, when looking up an existing transaction, the only thing you need to provide is a single ID. The transaction ID can be provided in the variables object.

This example uses the node query, which we cover in depth in the section Node Query.

{
  "query": "query($idVarName: ID!) {
    node(id: $idVarName) {
      ... on Transaction { status }
    }
  }",
  "variables": {
    "idVarName": "TRANSACTION_ID"
  }
}

Or variables can be omitted and it can be supplied inline in the query object.

{
  "query": "query {
    node(id: \"TRANSACTION_ID\") {
      ... on Transaction { status }
    }
  }"
}

The Client Mutation ID

If desired, you can use the client mutation ID to specify your own string ID for any operation. The same value that is passed in as the clientMutationId in input will be returned with the response. This field is available on all our input and response types.

Example request body:

{
  "query": "mutation ($input: VaultPaymentMethodInput!) {
      vaultPaymentMethod(input: $input) {
        clientMutationId
        paymentMethod {
          id
        }
      }
    }
  ",
  "variables:" {
    "input": {
      "clientMutationId": "my-id-for-this-operation-1234",
      "paymentMethodId": "SINGLE_USE_PAYMENT_METHOD_ID"
    }
  }
}

Example response:

{
  "data": {
    "vaultPaymentMethod": {
      "clientMutationId": "my-id-for-this-operation-1234",
      "paymentMethod": {
        "id": "NEW_MULTI_USE_PAYMENT_METHOD_ID"
      }
    }
  },
  "extensions": {
    "requestId": "a-braintree-generated-uuid-for-the-request"
  }
}

The Authorization Header

To authorize and authenticate a request to the API, use your gateway API keys. Compose your public and private key in the following format: PUBLIC_KEY:PRIVATE_KEY, and then Base64 encode them. One way to get the correct format is to run printf "PUBLIC_KEY:PRIVATE_KEY" | base64 from the command line.

Make sure to strip out all newline characters from the Base64-encoded value.

Authorization: Basic YOUR_BASE64ENCODED_PUBLIC_AND_PRIVATE_KEY

To use Braintree Auth credentials, you must obtain an access token via the OAuth flow. When you have an access token, use it via the Authorization header:

Authorization: Bearer YOUR_ACCESS_TOKEN

Under certain circumstances, you may want to access the client API. The client API is more limited in its scope and thus requires a lower level of authorization. In this case, your header should use a tokenization key.

Authorization: Basic YOUR_TOKENIZATION_KEY

The Braintree-Version Header

You will also need to provide a Braintree-Version header with a date in the format YYYY-MM-DD. We recommend using the date on which you begin integrating with the GraphQL API.

Braintree-Version: 2019-01-01

The Content-Type Header

The content type of a query should be application/json.

Putting It Together

Put all these pieces together and you're ready to make your first request to the Braintree GraphQL API:

curl \
 -H 'Content-Type: application/json' \
 -H 'Braintree-Version: 2019-01-01' \
 -H 'Authorization: Basic PUBLICKEY:PRIVATEKEY_BASE64ENCODED' \
 -X POST https://payments.sandbox.braintree-api.com/graphql \
 -d '{"query": "query { ping }", "variables": {} }'

A GraphQL request for a more complex mutation looks almost exactly the same, except in the post body:

curl \
 -H 'Content-Type: application/json' \
 -H 'Braintree-Version: 2019-01-01' \
 -H 'Authorization: Basic PUBLICKEY:PRIVATEKEY_BASE64ENCODED' \
 -X POST https://payments.sandbox.braintree-api.com/graphql \
 -d '{
    "query": "mutation($input: ChargePaymentMethodInput!) {
      chargePaymentMethod(input: $input) {
        transaction {
          id
          status
        }
      }
    }",
    "variables": {
      "input": {
        "paymentMethodId": "PAYMENT_METHOD_ID",
        "transaction": {"amount":"11.23"}
      }
    }
  }'

The Shape of a Response

A response from the GraphQL API will always return with HTTP status 200. The body of the response will determine whether or not an error occurred. Because you can send multiple queries and mutations in a single request, and because GraphQL includes the concept of a "partial success", the request may contain some successful data and some errors. The body is always JSON-formatted and may include any of the three top-level keys: data, errors, and extensions.

Data

A successful query will return a JSON-formatted response with the data you requested in your original query. Each key in the response will exactly match those specified and named in the query.

A successful ping request as outlined above should return:

{
  "data": {
    "ping": "pong"
  },
  "extensions": {
    "requestId": "a-uuid-for-the-request"
  }
}

Errors

Unlike a conventional REST API, GraphQL APIs do not rely on HTTP status codes as a way to convey the status of a request. Our GraphQL API should always return a JSON body with the 200 status code, even when there are errors.

If an error occurred, the response body will include a top-level errors object that describes the error or errors. For example, the response for charging an payment method with an invalid credit card number would be:

{
  "data": {
    "chargePaymentMethod": null
  },
  "errors": [
    {
      "message": "Credit card number is invalid.",
      "path": ["chargePaymentMethod"],
      "extensions": {
        "errorType": "user_error",
        "errorClass": "VALIDATION",
        "legacyCode": "81715",
        "inputPath": ["input", "paymentMethodId"]
      }
    }
  ],
  "extensions": {
    "requestId": "a-uuid-for-the-request"
  }
}

An error from the GraphQL API will have the following values:

  • message: The human-readable error message. This value is not intended to be parsed and may change at any time.
  • path: The GraphQL query or mutation causing the error.
  • extensions: Additional information about the error including...

    • errorClass: The classification of the error. Can be one of...
    • AUTHENTICATION
    • AUTHORIZATION
    • INTERNAL
    • UNSUPPORTED_CLIENT
    • NOT_FOUND
    • NOT_IMPLEMENTED
    • RESOURCE_LIMIT
    • SERVICE_AVAILABILITY
    • VALIDATION
    • legacyCode: A unique code identifying the error, which can be used to look it up in our documentation
    • inputPath: The input field responsible for the error.

Errors can manifest as type validation errors (e.g. provided a string for an integer field), Braintree validation errors (e.g. invalid credit card number), or errors reflecting upstream issues.

It is possible to have partially successful responses, where both a partially populated data object and errors are returned. If errors prevent a field in your query from resolving, the field in the data object will be returned with the value null and relevant errors will be in the error object.

Extensions

In addition to data and errors, an extensions object also is present on the API response. Each request you make to the GraphQL API will have a requestId in the extensions. This requestId value is unique to the request and is useful to Braintree Support should you need help debugging a request.

Using GraphiQL

We've integrated the GraphiQL project into our GraphQL documentation to allow you to explore the API in your browser using your Sandbox API credentials. GraphiQL is a graphical interactive IDE for exploring and playing around with GraphQL APIs.

You can use it via the API Explorer on this site, or with the desktop application, to interact with the API in real time.

To access the API, authenticate with your Sandbox login credentials. From there, you can browse the schema documentation and live code queries and mutations. If you don't have a Sandbox account, you can create one and it will be immediately available for use.

Rather than passing in a JSON-formatted string, as we show in the examples above, the GraphiQL explorer expects plain GraphQL queries and JSON-formatted variables to be entered in separate windows. We will follow this "plain" GraphQL formatting in our guides, so you can easily test-drive queries and mutations in GraphiQL. Just remember to use JSON-formatting when handling your own HTTP requests outside of GraphiQL.