MyPaymentNetwork

Core Txn Upgrade Guide to GraphQL

Introduction

The GraphQL API is the replacement for the Core Txn platform. 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 techsupport@schoolpay.com 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://dev.schoolpay.com/services/graphql
Using any valid API grant, send your username and password using basic auth.
Content type must be application/json.

You can pull the schema using dev. 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.

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.

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": "ryan@mypaynet.com",
      "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": "ryan@mypaynet.com",
          "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.