Skip to main content

Making API Calls

This guide covers how to make API calls by combining basic GraphQL ideas with Braintree-specific API details.

Because Braintree GraphQL requests are over HTTP, many examples in our guides use curl so you can start testing the API from the command line. We expect you will then pick the HTTP library of your choice for application development.

In the rest of the document, we use MUST, SHOULD, and MAY according to RFC 2119.

Endpoints

All requests (queries and mutations) go to a single HTTP endpoint.

For the sandbox test environment:

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

and the live production account:

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

You SHOULD use the POST method for all requests.

Request Requirements

The Authorization Header

To use the API, you MUST have a registered Braintree account and include your credentials in the Authorization header.

API Keys

This is the option many integrations use. After you generate an API Key, you MUST Base64-encode it for GraphQL requests.

If your public key is v4ndq314c2s5c28r and your private key is 93b78bc88be90d93ac282e50ae569fd6, you can generate your Base64-encoded token like this:

echo -n "v4ndq314c2s5c28r:93b78bc88be90d93ac282e50ae569fd" | base64

which produces djRuZHEzMTRjMnM1YzI4cjo5M2I3OGJjODhiZTkwZDkzYWMyODJlNTBhZTU2OWZk. The full header you present for authentication and authorization is:

Authorization: Basic djRuZHEzMTRjMnM1YzI4cjo5M2I3OGJjODhiZTkwZDkzYWMyODJlNTBhZTU2OWZk

Braintree Auth

(This is currently in closed beta). 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

Tokenization Keys

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: Bearer YOUR_TOKENIZATION_KEY

The Braintree-Version Header

You MUST 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 MUST be application/json.

Content-Type: application/json

The Message Body

The message body MUST be a JSON object. It MUST contain a query key and MAY contain a variables key.

The value for query MUST be a single JSON string containing a well-formed GraphQL document (query or mutation).

If you reference variables in your GraphQL document, the value for variables MUST be a JSON object containing the key/value pairs for each variable.

{
 "query": "a GraphQL document goes here that references $var1, $var2, and $var3",
 "variables": {
   "var1": 10,
   "var2": { "some": "data", "for": "var2" },
   "var3": ["a","list","of","values"]
 }
}

Your First Request

The simplest request is ping. It is mainly useful to ensure you understand how to generate well-formed requests.

Here's the GraphQL query:

query {
  ping
}

To send that to our API, it has to be wrapped in a JSON object with a query key:

{ "query": "query { ping }" }

And here's how it all fits together, using curl:

curl \
 -H 'Authorization: Basic BASE64_ENCODED(PUBLIC_KEY:PRIVATE_KEY)' \
 -H 'Braintree-Version: 2019-01-01' \
 -H 'Content-Type: application/json' \
 -X POST https://payments.sandbox.braintree-api.com/graphql \
 -d '{"query": "query { ping }"}'

You should receive this response:

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

A More Interesting Request

Here is a typical request body for the chargePaymentMethod mutation (Note: we have added newlines for readability but normally, JSON strings MUST escape newlines):

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

Per standard GraphQL, the input key in the variables section binds to the $input variable defined by the mutation in the query section and should represent the ChargePaymentMethodInput type.

The Client Mutation ID

You MAY use the client mutation ID to specify your own string ID for any mutation 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. We provide this for compliance with the Relay Input Object Mutations Specification.

Two Mutations In One Call

By using GraphQL aliases, we can make multiple charges in a single call to the API:

Example request body:

{
  "query": "mutation twoChargesAtOnce($tx1: ChargePaymentMethodInput!, $tx2: ChargePaymentMethodInput!) {
    firstTransaction: chargePaymentMethod(input: $tx1) {
        clientMutationId
        transaction {
          amount { value currencyIsoCode }
        }
      }
    secondTransaction: chargePaymentMethod(input: $tx2) {
        clientMutationId
        transaction {
          amount { value currencyIsoCode }
        }
      }
   }" ,
  "variables": {
    "tx1": {
      "clientMutationId": "tx1-mutation",
      "paymentMethodId": "fake-valid-visa-nonce",
      "transaction": {
        "amount": "11.25"
      }
    },
    "tx2": {
      "clientMutationId": "tx2-mutation",
      "paymentMethodId": "fake-valid-amex-nonce",
      "transaction": {
        "amount": "11.23"
      }
    }
  }
}

Example response:

{
  "data": {
    "firstTransaction": {
      "clientMutationId": "tx1-mutation",
      "transaction": {
        "amount": {
          "value": "11.25",
          "currencyIsoCode": "USD"
        }
      }
    },
    "secondTransaction": {
      "clientMutationId": "tx2-mutation",
      "transaction": {
        "amount": {
          "value": "11.23",
          "currencyIsoCode": "USD"
        }
      }
    }
  },
  "extensions": {
    "requestId": "TdTMiKZ1YBlBzSxLHSTEAQ1y3P3UbZCZue0NuDz4yLReE0_09dBOGg=="
  }
}

Understanding Responses

A response from the GraphQL API will always return with HTTP status 200. The JSON body of the response explains whether 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 a mix of data and error messages. The body is always a JSON object and MAY include any of the three top-level keys: data, errors, and extensions.

Data

A successful query MUST return a JSON object with a data key whose value is a JSON object with the data you requested. Each key in the data object will exactly match those specified in the query.

Errors

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

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

{
  "data": {
    "chargePaymentMethod": null
  },
  "errors": [ {
    "message": "Unknown or expired single-use payment method.",
    "locations": [ {
      "line": 2,
      "column": 7
     } ],
    "path": [ "chargePaymentMethod" ],
    "extensions": {
      "errorType": "user_error",
      "errorClass": "VALIDATION",
      "legacyCode": "91565",
      "inputPath": [ "input", "paymentMethodId" ]
    }
  }],
  "extensions": {
    "requestId": "a-uuid-for-the-request"
  }
}

An element of the errors array follows the GraphQL spec and 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.
  • locations: An array of { "line": x, "column": y } objects that describe where the error was detected during parsing of the GraphQL query. This is typically only used by interactive viewers such as GraphiQL, including our API Explorer.
  • path: The GraphQL query or mutation causing the error.
  • extensions: Additional information about the error including...

    • errorType: A deprecated field, please refer to errorClass instead.
    • 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 GraphQL 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

The API response MUST contain an extensions object. This object contains at least a requestId entry that is unique to the request and 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. Unless we are providing curl examples, 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.