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. There are different types of credentials you can use to authorize depending on what you'd like to do. For instance, client tokens and tokenization keys are restricted to certain mutations and queries that generally don't involve money movement, such as tokenizing payment details. Other operations, such as vaulting and charging payment methods, require API Key authentication.

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 93b78bc88be90d93ac282e50ae569fdd, you can generate your Base64-encoded token like this:

echo -n "v4ndq314c2s5c28r:93b78bc88be90d93ac282e50ae569fdd" | base64

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

Authorization: Basic djRuZHEzMTRjMnM1YzI4cjo5M2I3OGJjODhiZTkwZDkzYWMyODJlNTBhZTU2OWZkZA==

Tokenization Keys

A tokenization key is a lightweight, reusable value that can authorize your client to tokenize payment methods. You can view your tokenization keys in the Control Panel. To authorize using a tokenization key, pass it in the Authorization header:

Authorization: Bearer YOUR_TOKENIZATION_KEY

Authorization Fingerprints

Another way to authenticate from your client is via an authorization fingerprint from a client token. A client token contains an authorization fingerprint, which is a signed JWT, and is generated on your server with a lifetime of 24 hours. To obtain an authorization fingerprint you must Base64 decode a client token, the decoded client token will contain an authorizationFingerprint value, which can then be passed in the Authorization header.

For instance, once you obtain a client token, it can be decoded:

echo -n YOUR_CLIENT_TOKEN | base64 -D

This will produce a JSON value, similar to this:

{
"version": 2,
"environment": "sandbox",
"authorizationFingerprint": YOUR_AUTHORIZATION_FINGERPRINT
}

Your client is responsible for obtaining an authorization fingerprint from your server and can pass it in the Authorization header:

Authorization: Bearer YOUR_AUTHORIZATION_FINGERPRINT

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

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.

variables

{
"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

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:

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):

request body

{
"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.

Two Mutations In One Call

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

request body

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

response

{
"data": {
"firstTransaction": {
"transaction": {
"amount": {
"value": "11.25",
"currencyIsoCode": "USD"
}
}
},
"secondTransaction": {
"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:

errors

{
"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.

Timeouts

When using the GraphQL API, keep in mind that some requests (like creating transactions) can take longer than expected since they rely on communicating with a payment processor. We set a recommend setting a timeout of 60 seconds to accommodate for this. If you do not want to wait this long, you can set a custom timeout via the client you are using to form a request to the GraphQL API. However, if this timeout is less than 60 seconds, your client may trigger a timeout exception and you may not see the result of the request.

For example, let's say you set the timeout to 10 seconds, and you create a transaction request. If the request has not completed successfully at 10 seconds, your client will timeout. However, if the transaction then completes successfully at 19 seconds, the customer will be charged, but you will not receive any notification of this. You will need to search for the transaction to confirm if it was created and verify its status.

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.