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

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.

Query
mutation Payment($txn: ProcessTxnInput!) {
  ProcessTxn(Txn: $txn) {
    Errors {
      Message
    }
    TxnArray {
      ID
      Status
      Amount
      PayerName
      PayerEmail
      TxnItem {
        CustomFields {
          Key
          Value
        }
      }
    }
  }
}
Variables
{
  "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"
      }
    ]
  }
}
Response
{
  "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
query GetRefundState($txnid: ID!) {
  Txn(first: 1, Search: { ID: [$txnid] }) {
    edges {
      node {
        ID
        Amount
        AmountRefundable
        AmountAlreadyRefunded
        Status
        TxnItem {
          ID
          Quantity
          Amount
          AmountRefundable
          AmountAlreadyRefunded
        }
      }
    }
  }
}
Variables
{
  "txnid": "6617443"
}
Response
{
  "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.

Query
mutation ProcessRefund($refund: TxnUndoInputType!) {
  TxnUndo(TxnUndoInput: $refund) {
    Status
    Message
    OriginalTxn {
      ID
      Amount
      AmountRefundable
      AmountAlreadyRefunded
    }
    RefundTxn {
      ID
      Amount
      Status
    }
  }
}
Variables
{
  "refund": {
    "TxnId": "6617442",
    "EntireTxn": false,
    "UndoOperation": "Refund",
    "TxnUndoItem": [
      {
        "Amount": "5.00",
        "Quantity": 1
      }
    ]
  }
}
Response
{
  "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.

Go Live