Home / GraphQL API
The Highnote API uses GraphQL to enable modern integrations and experiences. GraphQL gives developers the flexibility to tailor requests to their use cases while providing type-safety over the network – all with a best-in-class tooling ecosystem.
GraphQL is not a query language for databases. It's an API pattern that cleanly expresses the behavior and modeling of a system. Using GraphQL, clients request data specific to their use case and receive predictable responses.
Documentation and developer experience is at the heart of GraphQL. In fact, documentation is built-in. GraphQL services are <a target=_blank href="https://graphql.org/learn/introspection/">introspectable</a> – this means they describe the operations and types available to developers in a way that allows for powerful tooling to streamline the development cycle. You can explore the Highnote API via the Highnote GraphQL Explorer or see clients & codegen for more.
While GraphQL has a rich ecosystem of tools, it does not require special libraries or frameworks to use. When integrating with the Highnote API, you will be sending and receiving JSON over HTTP.
The Using the Highnote API section covers Highnote API basics like request URLs, authentication, and more.
query HelloHighnote { ping }
GraphQL is a specification that provides a type system to ensure a contract between clients and servers.
The GraphQL type system provides five scalar types or primitive values: Int
, Float
, String
, Boolean
, and ID
. It also allows for custom scalar types. At this time, the Highnote API does not use custom scalars.
GraphQL APIs are introspectable. This means that they publish information about their capabilities to clients. The Highnote API is fully introspectable (to authenticated users) in the Test environment.
Tools such as graphiql use introspection to render documentation, type hints, and client-side validations. You can try it out with the Highnote GraphQL Explorer.
GraphQL provides three operations – query, mutation, and subscription. These are actions you can take against the API. While there are nuances to each, for the most part, queries are used to fetch data, and mutations are used to write data. The Highnote API does not currently use subscriptions.
The Highnote API uses Node queries and Global IDs as a means to look up individual objects.
In GraphQL, the node query is a pattern that allows clients to pass a global ID and not have to specify the entity it represents. Instead of fetching objects by resource, any object in the system that implements the Node
interface can be retrieved with one query.
query NodeQuery { node(id: "PAYMENT_CARD_ID") { ... on CardProduct { __typename id name } ... on PaymentCard { __typename id last4 } } }
You must provide a fragment in your selection set (what data you ask to get back) for each type you may expect.
In the above example, if the ID resolved to a PaymentCard
, the response would look like this:
{ "data": { "node": { "__typename": "PaymentCard", "id": "PAYMENT_CARD_ID", "last4": "1234" } } }
You can see which types in the Highnote API implement the Node
interface by running this query:
{ __type(name: "Node") { possibleTypes { name description } } }
When querying listed data, it is oftentimes useful to limit the number of records returned in a response. Doing so allows for faster response times from the server and smaller payloads on the client. The Highnote API automatically paginates data following the Relay Cursor Connections Specification. In this pagination specification, the edges
field is used to obtain list of items where each item has a cursor
specifying its position in the list and a node
which contains the fields requested on the item.
To better understand how pagination works in the Highnote API, we'll take a look at a common use case using card products. Let's say you need a list of your organization's card products, and each card product in the list must include its id
, name
, usage
, and vertical
. Here is what the query would look like:
query ListCardProducts($first: Int, $after: String) { cardProducts(first: $first, after: $after) { edges { cursor node { __typename id name usage vertical } } pageInfo { startCursor endCursor hasNextPage hasPreviousPage } } }
Notice the variables we provide to the query: $first
and $after
. These variables are optionally provided to the query in order to let the Highnote API know which records to return. For example, to return a list of the ten most recently created card products for an organization, provide the first
variable in your query:
{ "first": 10 }
Now that a first
variable has been provided, the query returns the ten most recently created card products:
{ "data": { "cardProducts": { "edges": [ { "cursor": "dD0yMDIyLTEyLTIwVDE4JTNBMTUlM0E1NS4wOTUwMDAwMDBaJmk9cGRfY2YwNGNjYzc1YzlhNDNmYzhlOWViMTVlMmMxNGY5NzY", "node": { "id": "pd_JtxcCG3Y9Qx8gAfVBujHP7YEEQPGOGEW", "name": "Card 1", "usage": "MULTI_USE", "vertical": "COMMERCIAL_DEBIT" } }, { "cursor": "dD0yMDIyLTEyLTA5VDE3JTNBMjAlM0EzOC41NzQwMDAwMDBaJmk9cGRfMThhZTE1YWJlZWMzNGMwN2E1ODdhMzVlNGIxNjA0Njk", "node": { "id": "pd_U5TkiuMjz1mu0haQdERQ7nwlI6Bka3OP", "name": "Card 2", "usage": "SINGLE_USE", "vertical": "AP_INVOICE_AUTOMATION" } }, { "cursor": "dD0yMDIyLTEyLTA5VDE3JTNBMjAlM0EzMC43ODEwMDAwMDBaJmk9cGRfMzg3NTI3Y2ViMWY5NGYwNzg3NDE2ZTViNDAyZDU4NjM", "node": { "id": "pd_8ec9q3PzraRoeDa5UdlDBw2jHfP4Jsds", "name": "Card 3", "usage": "MULTI_USE", "vertical": "AP_INVOICE_AUTOMATION" } }, { "cursor": "dD0yMDIyLTEyLTA5VDE3JTNBMTElM0EwNC4xNTAwMDAwMDBaJmk9cGRfMmM4N2JlNmViNGViNDMwYWFjZDU3Y2Y0NWI2ODI4NDE", "node": { "id": "pd_jsrG55BIaAIldWndPO5P3P61yHlZQpgS", "name": "Card 4", "usage": "MULTI_USE", "vertical": "AP_INVOICE_AUTOMATION" } }, { "cursor": "dD0yMDIyLTEwLTMxVDIwJTNBMTUlM0E0Ni40NDUwMDAwMDBaJmk9cGRfNjI0NDc3YjcyZDljNGYzZWI5NWU1N2Q0ZDM2NzFhOWE", "node": { "id": "pd_KODNBgPrQqu4p3KBIx7F8r6dpkid0pc0", "name": "Card 5", "usage": "MULTI_USE", "vertical": "GENERAL_PURPOSE_RELOADABLE" } }, { "cursor": "dD0yMDIyLTEwLTMxVDIwJTNBMTUlM0EyMC44MTEwMDAwMDBaJmk9cGRfY2NkMGQxZTE0NzBmNDkxMjlhZWI3YzY3NTQyODYwOWM", "node": { "id": "pd_yzp92A6EsH9tNjW6DGROiRryfHyeH4uj", "name": "Card 6", "usage": "MULTI_USE", "vertical": "GENERAL_PURPOSE_RELOADABLE" } }, { "cursor": "dD0yMDIyLTEwLTMxVDE1JTNBNDMlM0EyNy45NjUwMDAwMDBaJmk9cGRfMDAyOTBmYzQxMWFlNDk0N2FmYTVhNjA5NDQ3ZTFiNzE", "node": { "id": "pd_Ojf2vtoyYne8ya2lEsykwPN4x4EoadSM", "name": "Card 7", "usage": "MULTI_USE", "vertical": "GENERAL_PURPOSE_RELOADABLE" } }, { "cursor": "dD0yMDIyLTA5LTI5VDIwJTNBNDElM0ExOC45MTAwMDAwMDBaJmk9cGRfYmUyNTNjZDU2ZjAyNDkwMThjZTFjMjE2ODU5NmE4NmY", "node": { "id": "pd_W5tHx8DqYJbiFjAbRJghUB42Wt7tI2Ng", "name": "Card 8", "usage": "MULTI_USE", "vertical": "GENERAL_PURPOSE_RELOADABLE" } }, { "cursor": "dD0yMDIyLTA5LTIzVDE0JTNBMzElM0ExMy43NTgwMDAwMDBaJmk9cGRfZDAzYmZlMjcxOTY3NDRlMmJhMGQxMjRkYzJiN2I3ZDM", "node": { "id": "pd_JTuTEFE7t4QvANQsVxvUexbEdlceNMxn", "name": "Card 9", "usage": "MULTI_USE", "vertical": "SECURED_COMMERCIAL_CREDIT" } }, { "cursor": "dD0yMDIyLTA5LTIzVDE0JTNBMzAlM0E1OS43ODcwMDAwMDBaJmk9cGRfMTgzNTI4NDgwNjhkNGFhMDg5Nzg5NTVlM2NkNmQzZGI", "node": { "id": "pd_7LIs7e5TPjrt95MS6LedCve4Zr1p97Fk", "name": "Card 10", "usage": "MULTI_USE", "vertical": "SECURED_COMMERCIAL_CREDIT" } } ], "pageInfo": { "hasPreviousPage": false, "hasNextPage": true, "startCursor": "dD0yMDIyLTEyLTIwVDE4JTNBMTUlM0E1NS4wOTUwMDAwMDBaJmk9cGRfY2YwNGNjYzc1YzlhNDNmYzhlOWViMTVlMmMxNGY5NzY", "endCursor": "dD0yMDIyLTA5LTIzVDE0JTNBMzAlM0E1OS43ODcwMDAwMDBaJmk9cGRfMTgzNTI4NDgwNjhkNGFhMDg5Nzg5NTVlM2NkNmQzZGI" } } } }
Note: Most queries in the Highnote API will assume a default value of 20
for the first
variable if one is not provided by the user.
To request the next ten card products, you must additionally provide the after
variable to your query. In this case, the after
variable will be the cursor of the last item in the previously returned list. This value is also conveniently available as the endCursor
value in pageInfo
on the previous response. Updating the query variables, we now have:
{ "first": 10, "after": "dD0yMDIyLTA5LTIzVDE0JTNBMzAlM0E1OS43ODcwMDAwMDBaJmk9cGRfMTgzNTI4NDgwNjhkNGFhMDg5Nzg5NTVlM2NkNmQzZGI" }
Performing the query again with the updated variables will return the next ten items in the list after the item with a cursor value specified in after
.
To learn more about making Highnote specific calls, see Using the API.
GraphQL itself is transport agnostic, but the Highnote API is served as JSON over HTTP(s).
If you are familiar with making HTTP requests that send and receive JSON, a GraphQL call should feel very familiar. The key differences with GraphQL are that you do not rely on HTTP verbs (GET
, PUT
, POST
, PATCH
, DELETE
, etc.) or multiple endpoints per resource. Instead, you make POST
requests to a single endpoint (/graphql
) and call specific queries or mutations to accomplish your task.
Note: While both GET
and POST
requests are valid, it is recommended to use POST
requests when interacting with the API.
Your request should contain a JSON
body containing: query
, variables
(optional), and operationName
(optional). The query
is the actual operation you want to run. In the following example, we want to call the ping
query. (this is just the Hello World call in our API). The variables
key is used to pass in dynamic data on each request and operationName
is used to specify an action in the case multiple queries are sent (read more here).
A call to the Highnote API will look like this:
curl -X POST \ -H 'Content-Type: application/json' \ -H 'Authorization: Basic <API_KEY>' \ --data '{"query":"query Ping {\n ping\n}"}' \ https://api.us.test.highnoteplatform.com/graphql
and will return a JSON payload with the following format:
{ "data": { "ping": "pong" }, "extensions": { "requestId": "REQUEST_ID" } }
The GraphQL ecosystem is incredibly vibrant and naturally focuses on developer and integrator experience.
When developing against GraphQL APIs, it is helpful to use a GUI tool that leverages introspection to provide documentation and type hints. Some of the tools we use include:
There are plugins available for various IDEs to make your development experience more seamless.
There are a number of tools to generate code from GraphQL APIs. At Highnote, we make heavy use of GraphQL Code Generator to generate TypeScript definitions and SDKs for use with GraphQL.