Obsolete SchoolPay API (“Core Txn”)
Core Txn is obsolete, and may stop working properly. These docs remain in place for reference of existing connections only. Please refer to our GraphQL API
This API implements transaction processing and reporting, and a few core objects.
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.
Note: Global Notes apply
Management
/glaccounts (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 |
Reports
/batches (GET) | List batches |
/glbatches (GET) | List batches grouped by GL accounts |
/txns (GET) | List transactions |
/txns/:id (GET)) | Return transaction detail for a specific transaction |
Structures
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.
Authentication
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. |
400 | VERSION_REQUIRED |
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 Batch.id 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=20130101&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 /glbatches 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
{“label”:”Arts & Crafts”,”number”:”10000040021”,”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 20140101, and the midnighttomidnight 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 commaseparated array of the values to the left that will only return data of that payment method. |
Sample Request
/gl-batches?start_date=20150101&end_date=20151228&payees=28,193&payment_methods=ACH,CC
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 commaseparated 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 itemlevel 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"},
"payment_method":"cc","credit_card":{"brand":"MasterCard","pan":"5454545454545454","expires":"0120","security_code":"123"},
"gl_account":"1","amount":"40.00","convenience_fee":"1.00","payee":"28"}
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 finegrained 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”,
items:[{“id”:”MPN12345671234568”,”amount”:”10.50”}]}
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 |
Structures
Bank Account
The bank account information can be validated by using an object of type
Mpn\Payment\Information\AchInformation
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. |
Batch
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 nonsplitsettlement 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 splitsettlement set up. |
total_count: int | The count of transactions in the batch. |
CreditCard
brand: Visa / MasterCard / AmericanExpress / Discover | Validation: on of Visa, MasterCard, AmericanExpress, Discover |
pan: string | Validation: length 1216 + 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 |
GLAccount
id: string | Unique Identifier |
label: string | Validation: required, length > 1 |
number: string | Validation: required, length > 1 |
GLBatch
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[ ] |
Payee
name: string | Required, length > 1 |
merchant_id: string | Required, length > 1 |
Payer
name: string | Minimum pattern of [azAZ]* [azAZ]* (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 |
Transactions
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 randomlygenerated token used to look up the card used to pay for a previous transaction. |
items: PurchasedItem[ ] | Specifies the item/receiptlevel details to be associated with the transaction, visible on itemlevel 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 |
Item/Change
id: int | Unique identifier for the item change. |
item_id: int | |
user_id: int | Anything you want! |
date: date | |
undoes: int | |
summary:ChangeSummary |
Item/ItemModel
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 HTMLcompatible 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 multiitem nature of this item. |
amounts: Amounts | Holds details pertaining to the amounts of this item. |
Student
number: string | Holds the districtunique student number. |
district_id: int | |
name: string | The student’s name. |
Purchased Item
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. |