Home / Highnote API
GraphQL is a query language for APIs that allows clients to request the exact data they need and nothing more. The Highnote API uses GraphQL to provide a flexible, modern, and secure integration experience. Highnote’s GraphQL offers several benefits:
To start using the Highnote API, use the Highnote GraphQL Explorer or see clients and codegen for more details. Using the Highnote API covers Highnote API basics like request URLs, authentication, and more.
The following snippet represents a basic GraphQL ping
query:
query HelloHighnote { ping }
At a high level, GraphQL starts with a defined type system that describes the types of data available on the server. The type system is used to handle queries and mutations from clients.
When a client sends a query to the server, the server parses it and validates it against the schema. The server then executes the query by resolving each field using a set of resolver functions. Resolver functions are responsible for retrieving the data from the underlying data sources. The resolver functions are executed in parallel, allowing the server to retrieve all required data efficiently.
Once all resolver functions have been completed, the server assembles the results into a single JSON object and sends it back to the client.
GraphQL provides three operations. Operations are actions you can take against the API. The GraphQL operations are as follows:
The Highnote API does not currently use Subscriptions.
GraphQL is a specification that provides a type system. The GraphQL type system provides five scalar types or primitive values:
Int
- Represents a signed 32‐bit numeric non‐fractional value.Float
- Represents signed double‐precision fractional values as specified by IEEE 754.String
- Represents textual data, represented as UTF‐8 character sequences.Boolean
- Represents true or false.ID
- Represents a unique identifier.GraphQL also allows for custom scalar types.
GraphQL APIs have an introspection system, meaning 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.
The Highnote API uses Node queries and Global IDs to look up individual objects.
In GraphQL, the Node query is a pattern that allows clients to pass a global ID without specifying 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. Refer to the following query for an example:
query NodeQuery { node(id: "PAYMENT_CARD_ID") { ... on CardProduct { __typename id name } ... on PaymentCard { __typename id last4 } } }
You must provide a fragment for each selection set for each type you may expect. A selection set represents the data you want to receive in the response.
In the previous 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, limiting the number of records returned in a response is helpful. 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 a list of items. Each item has a cursor specifying its position in the list and a node
containing the requested fields.
Let’s look at a common use case using card products to understand better how pagination works in the Highnote API. 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 let the Highnote API know which records to return. 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.
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" } } } }
You can add the after
variable to your query to request the next ten card products. In this case, the after
variable will be the cursor of the last item in the previously returned list.
This value is the endCursor
value in pageInfo
on the previous response. Updating the query variables, we now have the following:
{ "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 is transport agnostic, and 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 familiar.
GraphQL does not use HTTP verbs (GET
, PUT
, POST
, etc.) or have multiple endpoints per resource. Instead, you make POST
requests to a single endpoint (/graphql
) using specific queries or mutations.
Both GET
and POST
requests are valid, but it is recommended to use POST
requests when interacting with the Highnote API.
Your request should contain a JSON
body with the following:
query
- The actual operation you want to run when making a requestvariables
- Used to pass dynamic data in a request (optional)operationName
- Used to specify an action in the case multiple queries are sent (optional)In the following example, we want to call the ping
query, which is just the Hello World call in the Highnote API. The ping
query 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 dynamic and strongly enhances the experience of developers and integrators. As a result, GraphQL supports innovation and modern approaches to development.
When developing with GraphQL APIs, using a GUI tool that leverages introspection to provide documentation and type hints is helpful. Some of the tools we use include:
Plugins are available for various IDEs to make your development experience more seamless:
There are several tools to generate code from GraphQL APIs. At Highnote, we heavily use GraphQL Code Generator to generate TypeScript definitions and SDKs for use with GraphQL.