Searching for Objects
A node query can fetch information about a specific object given an ID, but if you want to fetch information about multiple objects of the same type, you can specify criteria in a search
query. The search
query returns the fields you can use to search for objects. The available types you can search for are defined in the Search
type.
Here's a typical search workflow:
- Specify the type of object to search and the fields you want back in the
query
. - Specify your search criteria in the
variables
. - POST to the GraphQL endpoint.
- Paginate through your results.
Here's an example transaction search:
- CURL
curl -H 'Content-Type: application/json' -H 'Authorization: Basic BASE64_ENCODED(PUBLIC_KEY:PRIVATE_KEY)' -H 'Braintree-Version: 2019-01-01' -X POST https://payments.sandbox.braintree-api.com/graphql -d '{
"query": "query Search($input: TransactionSearchInput!) {
search {
transactions(input: $input) {
pageInfo {
hasNextPage
startCursor
endCursor
},
edges {
node {
id
status
amount {
value
currencyIsoCode
}
}
}
}
}
}",
"variables": {
"input": {
"amount": {
"value": {
"greaterThanOrEqualTo": "10.00"
}
},
"status": {
"in": ["SETTLED", "VOIDED"]
}
}
}
}'
Constructing Searches
To construct a search query, first select the type you'd like to search for, request the fields you want to be returned in the node
field, request pageInfo
which allows you to paginate through your results, and then specify the search criteria.
Search criteria are specified through input fields and generally follow one of four patterns to specify the criteria by which you would like to filter the results of your search. If you specify multiple criteria, they are logically AND
'd together, so all criteria must be met in order for the search to match an object.
Searching for empty strings, null values, or empty lists is the same as omitting the search field altogether.
Ranges
Range searches support the operators is
, greaterThanOrEqualTo
, and lessThanOrEqualTo
. The SearchRangeInput
type is an example of the range criteria.
To specify transactions with 10.00 <= amount <= 1000.00
pass the following input:
- Variables
"variables": {
"input": {
"amount": {
"value": {
"greaterThanOrEqualTo": "10.00",
"lessThanOrEqualTo": "1000.00"
}
}
}
}
Timestamps
Timestamp searches support the operators greaterThanOrEqualTo
and lessThanOrEqualTo
. The SearchTimestampInput
type is an example of the timestamp criteria.
The following would look for objects created between January 1, 2019, 6am UTC and January 3, 4pm UTC:
- Variables
"variables": {
"input": {
"createdAt": {
"lessThanOrEqualTo": "2019-01-03T16:00:00+00:00",
"greaterThanOrEqualTo": "2019-01-01T06:00:00+00:00"
}
}
}
Multiple Value Fields
Fields that accept multiple values support the operator in
. The SearchValueInput
, SearchTransactionStatusInput
, and SearchDisputeTypeInput
types are all examples of the multiple value field criteria.
For example, to search for transactions that have a status of either SETTLED
or VOIDED
you could pass the following input to the search query:
- Variables
"variables": {
"input": {
"status": {
"in": ["SETTLED", "VOIDED"]
}
}
}
Free Text Searches
Free text searches support the operators is
, isNot
, startsWith
, endsWith
, and contains
. The SearchTextInput
type is an example of a free text search criteria.
For example, the following input could be provided to find customers whose first name starts with "Jo"
:
- Variables
"variables": {
"input": {
"firstName": {
"startsWith": "Jo"
}
}
}
Note regarding isNot
: An empty string or null value for isNot
is equivalent to omitting the field altogether. It will not search for all results where the criteria is not null/empty.
Putting it all together
If you wanted to search for all transactions in February, 2019, greater than $100, that are SETTLED
and have an orderId starting with "cat-food":
- CURL
curl -H 'Content-Type: application/json' -H 'Authorization: Basic BASE64_ENCODED(PUBLIC_KEY:PRIVATE_KEY)' -H 'Braintree-Version: 2019-01-01' -X POST https://payments.sandbox.braintree-api.com/graphql -d '{
"query": "query Search($input: TransactionSearchInput!) {
search {
transactions(input: $input) {
pageInfo {
hasNextPage
startCursor
endCursor
},
edges {
node {
id
status
amount {
value
currencyIsoCode
}
orderId
}
}
}
}
}",
"variables": {
"input": {
"createdAt": {
"greaterThanOrEqualTo": "2019-02-01T00:00:00+00:00",
"lessThanOrEqualTo": "2019-03-01T00:00:00+00:00"
},
"amount": {
"value": {
"greaterThanOrEqualTo": "100.00"
}
},
"status": {
"in": ["SETTLED"]
},
"orderId": {
"startsWith": "cat-food"
}
}
}
}'
Understanding Your Results
Braintree's GraphQL API implements the Relay Cursor Connections Specification for presenting paginated search results. To read more about how connections are used throughout our API, see the Pagination and Relay Connections guide. Relay uses cursors for managing pagination, you must use a returned cursor as a parameter to access the next page of results, all of which will be logically after the cursor provided.
Here's a query to get back your transactions without any filtering (search criteria). By default, the API returns the maximum results per page, 50. Here, we've asked for just the first three results, and only the ID and transaction status:
- Graphql
query {
search {
transactions(input: {}, first: 3) {
pageInfo {
hasNextPage
startCursor
endCursor
}
edges {
cursor
node {
id
status
}
}
}
}
}
The server responds:
- Response
{
"data": {
"search": {
"transactions": {
"pageInfo": {
"hasNextPage": true,
"startCursor": "MTktMTAtMDhUMjA6MTA6MzRa",
"endCursor": "MTktMDktMjNUMTM6NTE6MDNa"
},
"edges": [
{
"cursor": "MTktMTAtMDhUMjA6MTA6MzRa",
"node": {
"id": "dHJhbnNhY3Rpb25fZzN5Z2NmM2c",
"status": "SETTLED"
}
},
{
"cursor": "MTktMDktMjNUMTM6NTc6NDha",
"node": {
"id": "dHJhbnNhY3Rpb25fZ2VoMnY2dmc",
"status": "SETTLED"
}
},
{
"cursor": "MTktMDktMjNUMTM6NTE6MDNa",
"node": {
"id": "dHJhbnNhY3Rpb25fZDFuZDVhdzM",
"status": "SETTLED"
}
}
]
}
}
},
"extensions": { "requestId": "D48-CkB2SQkhnw==" }
}
The objects you've searched for are contained in the list edges
. Each edge
is a node
of the data we requested (ID and status) and a cursor representing that node
's position in the edges
list. In pageInfo
, the startCursor
is the same as the cursor for the first result, the endCursor
is the same as the cursor of the last result. Since hasNextPage
is true
, we know there are more results. Let's ask for the next three results after endCursor
:
- Graphql
query {
search {
transactions(input: {}, first: 3, after: "MTktMDktMjNUMTM6NTE6MDNa") {
pageInfo {
hasNextPage
startCursor
endCursor
}
edges {
cursor
node {
id
status
}
}
}
}
}
And we get the next three items.
- Response
{
"data": {
"search": {
"transactions": {
"pageInfo": {
"hasNextPage": true,
"startCursor": "MTktMDktMjNUMTM6NDQ6MzZa",
"endCursor": "MTktMDktMjNUMTM6MzE6MjBa"
},
"edges": [
{
"cursor": "MTktMDktMjNUMTM6NDQ6MzZa",
"node": {
"id": "dHJhbnNhY3Rpb25fa21wMXBjdG0",
"status": "SETTLED"
}
},
{
"cursor": "MTktMDktMjNUMTM6NDQ6MTda",
"node": {
"id": "dHJhbnNhY3Rpb25fazNtaG42ZnI",
"status": "SETTLED"
}
},
{
"cursor": "MTktMDktMjNUMTM6MzE6MjBa",
"node": {
"id": "dHJhbnNhY3Rpb25fZzZremNidm0",
"status": "SETTLED"
}
}
]
}
}
},
"extensions": {
"requestId": "uVWGQkzkKlHd-Q=="
}
}
Empty Results
If you make a query for which there are no results, the edges
array will be empty, hasNextPage
will be false
, and startCursor
and endCursor
will be set to null
. For example:
- Response
{
"data": {
"search": {
"transactions": {
"pageInfo": {
"hasNextPage": false,
"startCursor": null,
"endCursor": null
},
"edges": [ ]
}
}
},
"extensions": {
"requestId": "w8QZkYHDMho5gw=="
}
}