GraphQL API
The GraphQL API is the latest generation of SchoolPay’s general purpose data access API’s. It provides full access to reporting, transaction processing, and item data. It is the replacement to the core REST API’s.
It allows more flexibility with return types, has much more capability to be optimized, it has only one entry point, it utilizes strongly type-safed system, operates in UTC, can automatically generate boilerplate code using a compatible library, field-level visibility, monitoring, and denial, and more benefits. We are phasing out the use of the Core Txn API in favor of these benefits.
Warning: The GraphQL API does have field-level limiting capabilities. This is designed to meet district’s ever-increasing privacy rules, and should not be a rationale to use the Core Txn API. Some customers may disclose the scope of data shared and even request to restrict your account to not return some data that you may have programmed to use. To prevent this, we recommend you only pull fields you need, and not fields you’d like to have just to have.
GraphQL is a standard API language, but it’s still relatively new. If you need any help at all developing, please let us know at [email protected] and we will get you over any hurdle you need. As a quick primer, the core concept of GraphQL is that you are querying the system as if it is a data structure, resolving nested parameters like joins, and retrieving only the data you need. A query has two inputs, the query itself, which is a hard-coded string, variables, which is a JSON object which matches data to placeholders in the query. With inputs, you can mix and match hard-coded and variable inputs to make a minimized interface into your system. SchoolPay tech support can help you write these commands.
Endpoints
- Production: https://api.schoolpay.com/services/graphql
- Development: https://schoolpayqa.com/services/graphql
- Demo Username: demo
- Demo Password: ef013a426fe7bab64a132c0996ed4783a13f615562762afefebbeb8dcaff6dd5
Using any valid API grant, send your username and password using basic auth.
You can pull the schema using the development endpoint. Schema introspection is disabled against production, it will not work there. Schema json files are also available upon request. Libraries can generate GraphQL classes and functions from queries. We’ve had success with Apollo-codegen creating Swift (for iOS) and typescript classes, then using Retyped to convert typescript classes into C# classes (for Windows). We’ve also had success with Windows just creating classes and using Newtonsoft JSON and using DeserializeObject.
Schema
Click here to see the entire schema
Processing Transactions
The Core Txn API is surprisingly similar to the GraphQL API when processing transactions, however, the GraphQL API has a few improvements you should be aware of.
- More robust support for GL accounts. GL accounts are now fully optional, and you can send both primary and secondary accounts. It is still recommended that if you can send them, you should, but it’s a little easier now if you have no capability of doing so.
- Better itemization support. When you create your first transaction in an account, an item to transact against is created transparently for you, and subsequent purchases are logged against this item. If you want to manually itemize on your end, however, you will need to implement to ProcessCart instead of ProcessTxn, contact tech support for more information. Core Txn had no real support for itemization, so we won’t cover that here.
- Flattened PaymentData object. We no longer nest any form-level input fields (PayerName, CcPan, etc.).
- Receipting is possible when using ProcessCart.
- Better error messaging, including item-level failures (if itemized).
- Times are returned in UTC now and use a different format.
- Amounts are rejected if not in the form ^\d+.\d\d$
- Warning: It is possible a SchoolPay account is configured to automatically assess a convenience fee, when this is the case it is not possible to avoid and amounts submitted will likely be higher than you expect. These settings can be queried on the Company so you know what to expect. The Process Txn mutation does not support previewing, so it is not currently possible to check to see if a fee will be added.
mutation Payment($txn: ProcessTxnInput!) {
ProcessTxn(Txn: $txn) {
Errors {
Message
}
TxnArray {
ID
Status
Amount
PayerName
PayerEmail
TxnItem {
CustomFields {
Key
Value
}
}
}
}
}
{
"txn": {
"PaymentData": {
"PaymentMethod": "CC",
"CcPan": "4111111111111111",
"CcExpire": "1220",
"CcCvv": "123",
"PayerName": "Ryan Knuesel",
"PayerEmail": "[email protected]",
"PayerZip": "53703"
},
"Payee": 54276,
"GLAccounts": [
{
"AccountNumber": "1234",
"AccountLabel": "Test",
"Type": "Primary"
},
{
"AccountNumber": "4321",
"AccountLabel": "Test",
"Type": "Secondary"
}
],
"Amounts": {
"Total": "11.00",
"Subtotal": "9.20",
"ConvenienceFee": "0.80",
"Shipping": "0.75",
"Tax": "0.25"
},
"CustomFields": [
{
"Key": "CustomerID",
"Value": "a447058a-4aa4-11e9-bb2c-26bf4f4b8bd7"
},
{
"Key": "CartID",
"Value": "ba2b5c34-4aa4-11e9-bb2c-26bf4f4b8bd7"
}
]
}
}
{
"data": {
"ProcessTxn": {
"Errors": [],
"TxnArray": [
{
"ID": "1082",
"Status": "Pending",
"Amount": "11.00",
"PayerName": "Ryan Knuesel",
"PayerEmail": "[email protected]",
"TxnItem": [
{
"CustomFields": [
{
"Key": "CustomerID",
"Value": "a447058a-4aa4-11e9-bb2c-26bf4f4b8bd7"
},
{
"Key": "CartID",
"Value": "ba2b5c34-4aa4-11e9-bb2c-26bf4f4b8bd7"
}
]
}
]
}
]
}
}
}
Processing Refunds/Voids
The Core Txn was built on a framework that could only return a single object no matter what happened, and if any exception was handled error messaging was not supported, so refunding/voiding a transaction always felt a little odd, and was counter-intuitive to do. In the GraphQL API, refunding and voiding makes more sense. A notable change to this endpoint is you can now retrieve error messages, as well as both the OriginalTxn and the RefundTxn.
You can always use the transaction report query to get the refundable state of a transaction, but I can’t recommend if you should or not, that’s up to your application. Here’s GetRefundState.
query GetRefundState($txnid: ID!) {
Txn(first: 1, Search: { ID: [$txnid] }) {
edges {
node {
ID
Amount
AmountRefundable
AmountAlreadyRefunded
Status
TxnItem {
ID
Quantity
Amount
AmountRefundable
AmountAlreadyRefunded
}
}
}
}
}
{
"txnid": "6617443"
}
{
"data": {
"Txn": {
"edges": [
{
"node": {
"ID": "6617443",
"Amount": "254.00",
"AmountRefundable": "9.80",
"AmountAlreadyRefunded": "244.20",
"Status": "Pending",
"TxnItem": [
{
"ID": "8367996",
"Quantity": 1,
"Amount": "232.10",
"AmountRefundable": "-12.10",
"AmountAlreadyRefunded": "244.20"
}
]
}
}
]
}
}
}
Once you know the refundable state, or if you simply don’t care about it, you can execute the TxnUndo mutation. TxnUndos can be done against the entire transaction or for part of a transaction. There are limitations to this system though:
Voids can only be EntireTxn, as they pull the transaction out of the settlement batch instead of adjust the amount of the transaction. Voids do not carry a transaction fee, and can only be executed prior to settlement (Status = Pending). Txns containing a single item can be partially refunded without specifying an item ID. The system will simply allocate the refund to the only item available. Txns with more than one item can only be partially refunded by supplying item ID’s on which to allocate the refunded portion. Refunds do carry a transaction fee and can only be executed after settlement (Status = Settled). You can void a refund to cancel it.
mutation ProcessRefund($refund: TxnUndoInputType!) {
TxnUndo(TxnUndoInput: $refund) {
Status
Message
OriginalTxn {
ID
Amount
AmountRefundable
AmountAlreadyRefunded
}
RefundTxn {
ID
Amount
Status
}
}
}
{
"refund": {
"TxnId": "6617442",
"EntireTxn": false,
"UndoOperation": "Refund",
"TxnUndoItem": [
{
"Amount": "5.00",
"Quantity": 1
}
]
}
}
{
"data": {
"TxnUndo": {
"Status": "Success",
"Message": "Successfully refunded Txn.",
"OriginalTxn": {
"ID": "6617442",
"Amount": "254.00",
"AmountRefundable": "244.00",
"AmountAlreadyRefunded": "10.00"
},
"RefundTxn": {
"ID": "6617447",
"Amount": "5.00",
"Status": "Pending"
}
}
}
}
Reconciliation
Transaction reports, batch reports, and GL account totals are all available via the GraphQL API. Since there’s a lot of ways to reconcile, we won’t recommend any particular one here. You can play around with the Txn, Batch, or Batch { GLDistribution } queries gathered from the introspection and see what fits your needs. As always, reach out to tech support if you want custom advice.