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:
- Response
{
"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:
- GraphQL
query {
ping
}
To send that to our API, it has to be wrapped in a JSON object with a query
key:
- JSON
{ "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:
- Response
{
"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 documentationinputPath
: 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.