Core Txn is no longer recommended. Please view our New Guide for Upgrading to GraphQL

Core Transaction API

Implementing the bare necessities of processing transactions and reporting, this API does not cover any school­specific topics like student or item management.

Core Transaction Design Philosophy

While other core transaction processing systems use a design philosophy based upon operations succeeding or failing, SchoolPay is not like that. SchoolPay’s API is designed with microservice architecture in mind via stateless object updating.

Operations on a SchoolPay transaction return a SchoolPay transaction. Period. You will not be looking for “Refund request failed”, instead, you’d be looking for the transaction’s data fields pertaining to refunds to be updated. Errors only happen when a request fundamentally fails, or when something impossible is asked of the system. In any case, in these situations you would not have a returned transaction and could not trigger your update routine.

Design your system such that you have a central function, that takes two transaction objects, an old one and a new one. We recommend the following structure with a few canned checks, although your needs may vary.

	F(T, T′) => 
    If ( T.status = ‘Pending’ AND T′.status = ‘Settled’ ) then Transaction settled successfully
    If ( T.amount_refunded < T.amount_refunded ) then Refunded amount increased
    If ( T.status = ‘Settled’ AND T′.status = ‘Voided’ ) then Transaction has been voided
    If ( T.status = ‘Error’ ) then The transaction has errored somehow
    Update record for T to T′

Consider the following use case. You issue a refund for a transaction, and SchoolPay’s API times out, so you receive no response. What do you do? If you issue a transaction update via GET /txn/:id, then run F(T, T′), if the refund went through it will trickle through your system, otherwise you can call refund again.

Retry Failed Refunds

If ( T.needs_refund ) then
T′ = getTxn(T)
F(T, T′)
T = refresh T from your records
If ( T.needs_refund ) then
T′ = refund(T)
F(T, T′)


This also would allow you to push long-running operations into a queue, by pushing T′ into a queue such as Amazons SQS. This means that your update script doesn’t care at all about how it got there, either via a refund request, nightly status update, etc, the point is that once you get it there it determines what to do based on how the record changed.

Less code to write, less code to test. You do not need to parse the response of every operation, just try to turn it into a transaction. If you can’t, then treat it as an error. If you can, push it into your function for handling transaction mutations.

Global Notes

UTF-8 Encoding

Every string passed to and from the API needs to be UTF­8 encoded. For maximum compatibility, normalize to Unicode Normalization Form C (NFC) before UTF-­8 encoding.

Date Format

All dates in the API are strings in the following format:
“2010­-10­-21 22:31:20”

In code format, which can be used in all programming languages that support strftime or strptime:
%Y­%m­%d %H:%M:%S

Error Handling

Errors are returned using standard HTTP error code syntax. Any additional info is included in the body of the return call, JSON­formatted. Error codes not listed here are in the REST API methods listed below.

Remove non-ASCII characters from JSON

SchoolPay utilizes a framework that cannot handle extended characters in JSON. While this is annoying, it is easy enough to fix by preconditioning your API. You must escape all non-ascii characters in your JSON payloads or you will receive a 500 error.

Code Sample
asciiJSON.escapeNonAsciis = function(text) {
  var chars, code, i;

  chars = [];
  i = 0;
  while (i < text.length) {
    code = text.charCodeAt(i);
    if (code < 128) {
    } else {
      if (code < 256) {
      } else if (code < 4096) {
      } else {
  return chars.join('');

Standard API Errors

Code Description
400 Bad input parameter. Error message should indicate which one and why.
401 Not authorized
404 File or folder not found at the specified path.
405 Request method not expected (generally should be GET or POST).
500 Server Error


/gl­accounts (GET, POST) Add, remove, or list GL account
/payees (GET) List payee accounts

Process Payment

/txns (POST) Process a transaction
/txns/:id (POST) Reverse a transaction


/batches (GET) List batches
/gl­batches (GET) List batches grouped by GL accounts
/txns (GET) List transactions
/txns/:id (GET)) Return transaction detail for a specific transaction


Terminology - the term “chart of accounts” and “GL accounts” have been termed as equivalent terms, however, using the terminology “Chart of Accounts” in user interfaces is recommended in favor of using “GL account”, as it is more commonly used vernacular amongst customers. However, “Chart of Accounts” has no nice way to be referred to succinctly in code, so we use the term “GL account” in code.

Extensions -­ Whenever the product needs to do a significant amount of extra work, or return a significantly large amount of data, the features are disabled by default. These are called “extensions” and augment resources, but allow the implementor a certain amount of flexibility with optimizing his app.

Extensions are optimistically defined in the data structures portion of the document, but not every endpoint accepts them. You need to read the notes on your specific endpoint to see which extensions are accepted.

Best Practice

Never share your API access token and secret. Never transmit these values over unencrypted channels, such as http. Retrieval of your API access token and secret can be done from your administrative account at our website. Care should be taken to avoid logging or storing your API token and secret in insecure formats.

Maintain a flexible list of payees available to your account. This list is ultimately controlled by our management and your application should be able to react to changes in the list without needing to be rewritten.

In a nightly process, check batch totals with the /batches resource and compare it to the totals recorded on your side. This will give you a quick way to notice and respond to errors in the payment process.

Use GL accounts and the GL batches to logically organize groups of payments for individual payees. It is not uncommon for one bank account to be managed by multiple people with different responsibilities. If you have no need for this feature, all GL values are optional and not required to make payments.


All authentication is done via the Authentication HTTP header. The format is done in the standard:

Authentication: Basic base64(username:password)

If you do not provide this header, you will receive an error 401: Not Authorized.

Paged Lists

Some resources return paged lists. Any resource that returns a paged list can accept the following parameters

limit: int Number of records to return. This number should not exceed 100, and the default value is 30.
offset: int Number of records to skip before returning results. The default value for is 0.

Date Ranges

after: int The lower bound in a date range.
before: int The upper bound in a date range.

Global Errors

Any resource in our system can produce the following error.

400 INVALID_JSON You are sending us bad JSON
400 INVALID_FIELD A required field is missing or a field is in the wrong type.

GET /batches

Returns batch summary information for your companies. Open batches (batches that are still aggregating transactions) will NOT be reported. Batching is controlled by My Payment Network and batches typically occur at 12:00 am central time.

Caution: ​The field is a string​, NOT an integer.

Optional Parameters

payees: int[] Filters your results by payee. Accepts an ID that can be acquired through the payees resource.
after: DateTime Only returns results occurring after a specified date.
payment_method: ACH, CC, Cash, PhysicalCheck Only returns batches with credit card or check transactions. Physical Check and Cash are only used with SchoolPay's virtual terminal

Return Type: PagedList < Batch >

Sample Request
GET /batches?since=2013­01­01&payee=1234502 

Possible Errors

400 INVALID_PAYEE You are attempting to filter by a payee that does not exist.

GET /gl-accounts

Returns a list of GL accounts available to your application. This functionality is primarily meant to augment the functionality of the /gl­batches resource.

Please use the table batch_gl_totals.

Return Type: GLAccount[ ]

Sample Request
GET /gl-accounts 

POST /gl-accounts

Creates (or deletes) a GL account in your account. If you attempt to create an account that already exists, a success message will be emitted.

Required Parameters

label: string The human-­readable label of the GL account.
number: string The number of the GL account

Optional Parameters

remove: yes Remove this GL account specified by label and number.

Return Type: HTTP/1.1 204 No Content

Sample Request
POST /gl­accounts
{“label”:”Arts & Crafts”,”number”:”1000­004­0021”,”remove”:”yes”} 

Possible Errors

404 ACCOUNT_NOT_FOUND You are attempting to remove an account that doesn’t exist.

GET /gl-batches

As part of a bookkeeping routine, you can opt to (and we recommend) list your batches by GL account. This allows easier troubleshooting of reconciliation issues by isolating your problem to smaller sets. Returns a special batch report that is grouped by gl code, which can allow your application to work more flexibly with “just totals” and not require detailed information on every transaction.

Optional Parameters

start_date: Date Return batches that occur after the after date. Note that batch timestamps will not have hours, minutes, or seconds associated with them, so date arguments would be of the format 2014­01­01, and the midnight­to­midnight times are in CST.
end_date: Date Returns batches that occur before or on date.
payees Comma separated array of payee ID’s.
payment_methods: (ACH, CC, Cash, PhysicalCheck) Accepts a comma­separated array of the values to the left that will only return data of that payment method.

Sample Request

Return Type: PagedList < Batch >

Warning: this method may return more objects than expected. SchoolPay can be configured to break convenience fees, shipping, and tax amounts into separate batches. In these cases, for ease of implementation, they are simply simulated as additional results. Because of this, you may receive more objects than the supplied limit. When paginating this resource, you should wait until you have less than the limit of supplied results, and should not use == to compare the values. You should not count objects to calculate your offset, but rather, should simply multiply your hard-coded offset by the number of pages.

GET /payees

Returns information about the payee accounts available to your application.

Return Type: Payee [ ]

Sample Request

GET /payees 

GET /txns

Available Extensions: recurring, items

Returns detailed information about transactions. If the items extension is supplied, it will return detailed information about the items purchased.

Optional Parameters

payees: int[ ] Returns transactions only for the specified payees.
after: DateTime Returns transaction that happened after the date.
before: DateTime Returns transactions that happened before the date.
since: int Returns transaction with ID’s greater than this supplied value.
batch: int Returns transactions in a batch.
payment_method: (ACH, CC, Cash, PhysicalCheck) Accepts a comma­separated array of the values to the left that will only return data of that payment method.

Return Type: PagedList < Transaction >

Sample Request
GET /txns?since=1234567 

Possible Errors

400 INVALID_PAYEE You are attempting to use a payee that does not exist.

POST /txns

Processes a transaction. This method allows you to make payments against three total types of payment account: Bank Card, E check, and Stored Card. See the structure format for a Transaction for more. Please note that the way you program your application will directly impact the fees you will be charged. Not all transactions cost the same amount. We are not responsible for the fees you incur while using our services.

Itemized Transactions / Receipt Data

SchoolPay can take any number of “items” along with the transaction that will appear in item­level reporting across any SchoolPay service. To use this feature, specify the “items” key on your transaction object while processing your transaction. Your item total amounts must match the transaction total amounts in order to process.

Body Type

Transaction Specifying the transaction you want to process.

Return Type: Transaction

Sample Request
POST /txns
{"payer":{"name":"Ryan Knuesel", "email":"[email protected]", "street":"214 N Hamilton",
"city":"Madison", "state":"WI", "postal_code":"53703", "country":"USA"}, 

Possible Errors

400 INVALID_PAYEE You are attempting to use a payee that does not exist.
400 INVALID_GL You are attempting to use a GL account that does not exist.

GET /txns/:id

Returns a transaction.

Return Values: Transaction

Sample Request
GET /txns/1234567

Available Extensions

payer Looks up and returns information about the payer of this transaction. Adds the fields payer, bank_account, and credit_card.
gl Looks up and returns general ledger information about this transaction. Adds the field gl_account.

Possible Errors

404 TXN_NOT_FOUND Transaction specified by :id was not found.

POST /txns

Refund or void a transaction.

Required Parameters

operation: refund/void If this value is “refund”, and the transaction can be refunded, the transaction will be refunded, which will result in a transaction. If this value is “void” and the transaction can be voided, the transaction will be voided.
transaction_id: int The transaction to refund.
items: array An array of items to refund. Gives you fine­grained control over partial refunds resolving to the item level.

Optional Parameters

amount: decimal Specifies the amount to reverse from a transaction. If you do not specify an amount, the entire amount of the original transaction that has not yet been reversed will be reversed.
You cannot specify an amount if you intend to void a transaction.

Return Values: Transaction

Sample Request
POST /txns {“operation”:”refund”,”amount”:”10.50”,”transaction_id”:”1234567”,

Possible Errors

400 CANNOT_UNDO Attempting to void or refund a transaction that cannot be voided or refunded.
400 BAD_REFUND_AMOUNT Attempting to refund more than the original amount of the transaction, or refund amount is negative or zero.
400 TXN_ERROR Something went wrong at the service provider.
404 TXN_NOT_FOUND Transaction specified by :id was not found.

GET /items

Available extensions: description, data_fields

Item\ItemModel Structure

Name : Type Extension
recurring : Recurring Recurring
description: text/html Description
code: string
title: string
data_fields : DataField[ ] Data Fields
category: integer
gl_account: integer


Bank Account

The bank account information can be validated by using an object of type


routing_number: string Validation: Must be at least 6 numeric characters. Matches ABA validation routine.
account_number: string Validation: Must be at least 6 numeric characters.


id: string Batch identifier. Assigned by our processor after transaction deposit date.
payee: int The payee of the batch.
date: Date The date the batch is submitted to the processor.
payment_method: ACH, CC, Cash, PhysicalCheck The payment method of the batch
total_amount: amount The sum of all authorization amounts in the batch. This is the amount of the deposit in a non­split­settlement set up.
fees_amount: amount The sum of all convenience fees in the batch.
partial_amount: amount The total amount of the batch minus the fees amount of the batch. This is the amount of the deposit in a split­settlement set up.
total_count: int The count of transactions in the batch.


brand: Visa / MasterCard / AmericanExpress / Discover Validation: on of Visa, MasterCard, AmericanExpress, Discover
pan: string Validation: length 12­16 + Luhn. If first digit is X, card brand must be Y. 3: Amex, 4: Visa, 5: MC, 6: Discover
expires: string Validation: Must be valid date of format MMYY.
security_code: string Validation: Must be numeric of length: 4 for AmEx, 3 for Visa/MC/Discover

ErrorBody: No validations required

error: string
message: string


id: string Unique Identifier
label: string Validation: required, length > 1
number: string Validation: required, length > 1


gl_batch_identifier: string A unique identifier for the SchoolPay GL batch​.
date: Date The date of the batch.
batch_id: int The batch ID for this batch which is assigned by our payment processor.
payee_id: int The ID of the payee of the transactions in the batch.
gl_account: GLAccount The GL account of the transactions in the batch.
amount: decimal The total amount of all transactions in the batch.
amount_without_fees: decimal The total amount of all transactions in the batch minus and amounts designated as “fees”.
count: int The number of items sold in the batch.

PagedList < T >

offset: int
limit: int
objects: T[ ]


name: string Required, length > 1
merchant_id: string Required, length > 1


name: string Minimum pattern of [a­zA­Z]* [a­zA­Z]* (at least two names separated by a space with minimum length 1 each)
address: string Maximum length of 20, minimum length > 1
address2: string not required
email: string Must be an email address
phone: string Must be numeric, minimum length 10.
ip: inet_addr Must be a valid ipv4 internet address
city: string minimum length > 1
state: string 2-­letter code. Must be in file data/states.php IFF country = USA, otherwise, optional.
postal_code: string Must be numeric, minimum length 10.
country: string 3-­letter code. Must be in file data/coutries.php


id: int Returns the unique ID of a transaction.
order_id: int Returns a unique identifier for the order that the transaction was a part of.
payer: Payer
payment_method: ACH, CC, Cash, PhysicalCheck Must be ACH, CC, Cash, PhysicalCheck
credit_card: CreditCard required if payment_method is CC
bank_account: BankAccount required if payment_method is ACH
stored_card_retrieval_token: string minimum length > 1
gl_account: GLAccount Do not validate.
amount: decimal must be a valid formatted string between 1 and 100,000 and must contain two decimal places (4.00)
amount_refunded: decimal Do not validate
convenience_fee: decimal Same validation as “amount”
tax: decimal Same validation as “amount”
shipping: decimal Same validation as “amount”
payee: int Must be a company_id in the database.
status: Error / Pending / Settled / Voided / Refunded / Returned / Unknown / Declined Do not validate
status_message: string Do not validate
batch: int Do not validate
data: string Anything you want!
store_card: bool If set to true, the card will be stored and a token will be returned.
stored_card_retrieval_token: string This is a randomly­generated token used to look up the card used to pay for a previous transaction.
items: PurchasedItem[ ] Specifies the item/receipt­level details to be associated with the transaction, visible on item­level SchoolPay reports.

Transaction Status Details

Error A technical problem prevented us from processing this payment.
Pending The processor approved the transaction and it will settle at midnight.
Settled Money has moved from payer to payee for this transaction.
Voided The authorization was canceled. It will not settle. Can only happen when transaction is pending
Refunded Money has been moved from payee to payer for this transaction. can only happen after funds settle.
Returned The check was returned by the bank, much like with paper currency.
Unknown The payment processor sent an unclear response or timed out, and we cannot determine the status of this transaction at this time. It may have processed, it may have not.
Declined The payment was declined by the issuer


id: int Unique identifier for the item change.
item_id: int
user_id: int Anything you want!
date: date
undoes: int


id: int Unique identifier for the item.
company_id: int The owner/controller of the item.
payee_id: int The payee who would take payment for the item.
is_valid: bool Whether or not this item is valid.
title: string The tile of the item
description: string Requires the “description” expansion This is an HTML­compatible field that allows the description of an item to be input.
item_type: string The item type of the item. Valid values are Simple, Recurring, Food Service, and Multi.
sold_count: int The number of payments made against this item minus the number of reversals made against this item.
created_on: date The time at which the item was created.
updated_on: date The last time a field on this item was changed, with the exception of sold_count.
active_state: enum The state of the general availability of the item. Options are yes, no, yes_between_dates
is_parent_center: bool Determines if an item should be visible to parents using the parent center software.
can_be_purcahsed: bool Determines if an item can be purchased. It is a combination of active_state, active_before, active_after, and the current time.
active_after: date
active_before: date
category: int Category
gl_account: int GL Account
recurring: Recurring Holds details pertaining to the recurring nature of this item.
multi: Multi Requires the “multi” expansion Holds details pertaining to the multi­item nature of this item.
amounts: Amounts Holds details pertaining to the amounts of this item.


number: string Holds the district­unique student number.
district_id: int
name: string The student’s name.


id: string A unique identifier for the purchasd item.
item_name: string The name of the item purchased.
amount: decimal The amount of the item purchased.
gl_account: GLAccount The GL account associated with the item purchased.
student: Student The student associated with the item purchased.
custom_fields: # Returns a key/value map of the “custom fields” purchased with this item.