---
description: Learn how to build an API Perkville can connect to
---

# API requirements

## Overview

Thank you for your interest in integrating your POS/membership system with Perkville!

This document outlines the general API requirements and data we typically ingest from membership, scheduling, and point-of-sale systems when Perkville is integrating with your API. By following these guidelines, you’ll enable Perkville to detect new users in your system and track their activities.

We also offer an API that you can use to connect with Perkville:

{% embed url="https://www.perkville.com/developers/docs/v2/" %}

For any questions, feel free to reach out to us at support@perkville.com.

We’re here to help!

## Authentication

Your API should have an authentication scheme that allows us to store a key to authenticate requests on behalf of a specific business. We recommend using OAuth 2's "Authorization Code" grant type. You can refer to [this guide](https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type) for more details.

{% embed url="https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type" %}

You can also consider starting with a simple shared secret. A business can log into their account, find a secret key, and paste it into our application. We’d then use this key for every query.

Additionally, we require a separate key that uniquely identifies Perkville. If you create a custom authentication solution, ensure this key is included to distinguish our system from others that might integrate with your API.

## Resources

Your API should allow us to poll for newly added and modified records and perform actions based on the data received.

{% hint style="info" %}
A "resource" is a record that businesses care about, such as a "user" or "check-in."
{% endhint %}

### User

* **Fields:** User ID (Primary Key), Email, First Name, Last Name, Phone Number, Record Last Modified Datetime, (Boolean) Is Child User?, (User ID) Parent ID, and any other personal information.
* **Query by:** Batch primary key, Last modified datetime range.

### Location (Facility)

* **Fields:** Location ID (Primary Key), Location Name, Street Address, City, State, Zip Code, Timezone, Record Last Modified Datetime, and any other useful information.
* **Query by:** Complete transfer.

### Membership

* **Fields:** Membership ID (Primary Key), User ID (Foreign Key to User), Membership Type, Membership Status, Member Join Date, Cancellation Date, Home Location (Foreign Key to Location), Record Last Modified Datetime, and any other useful information.
* **Query by:** Batch primary key, Last modified datetime range.

### Gym Check-in

* **Fields:** Check-in ID (Primary Key), Check-in Datetime, Location ID (Foreign Key to Location), Member ID (Foreign Key to Membership), User ID (Foreign Key to User), Record Last Modified Datetime, and any other useful information.
* **Query by:** Last modified datetime range.

### Referral

* **Fields:** Referral ID (Primary Key), Referrer User ID (Foreign Key to User), Referee User ID (Foreign Key to User), Referral Datetime, Record Last Modified Datetime, and any other useful information.
* **Query by:** Last modified datetime range.

### Sales

* **Fields:** Sale ID (Primary Key), LineItem ID, LineItem Category ID, LineItem Category Name, LineItem Subcategory ID, LineItem Subcategory Name, LineItem Payment Type, Pre-Tax Price, User ID (Foreign Key to User), Member ID (Foreign Key to Membership), Location ID (Foreign Key to Location), Sale Datetime, Record Last Modified Datetime, and any other useful information.
* **Query by:** Last modified datetime range.

### Sales Category

* **Fields:** Category ID, Category Name, Location ID, and any other useful information.
* **Query by:** Complete transfer.

### Sales Subcategory

* **Fields:** Subcategory ID, Subcategory Name, Location ID, and any other useful information.
* **Query by:** Complete transfer.

### Class

* **Fields:** Class ID (Primary Key), Class Name, and any other useful information.
* **Query by:** Complete transfer.

### Class Attendance

* **Fields:** Class Attendance ID (Primary Key), Class ID, User ID (Foreign Key to User), Membership ID (Foreign Key to Membership), Location ID (Foreign Key to Location), Class Name, Class Datetime, Check-in Datetime, Attended/Checked-in Confirmation (if applicable), and any other useful information.
* **Query by:** Last modified datetime range.

### Appointment

* **Fields:** Appointment ID (Primary Key), Appointment Datetime, Check-in Datetime, User ID (Foreign Key to User), Membership ID (Foreign Key to Membership), Attended/Checked-in Confirmation (if applicable), and any other useful information.
* **Query by:** Last modified datetime range.

### Appointment Category

* **Fields:** Appointment ID, Appointment Name, Location ID (Filterable), and any other useful information.
* **Query by:** Complete transfer.

## Querying

Every API endpoint should require authentication and accept the two keys referenced above. Each endpoint should also support paging, ideally allowing up to 10,000 records per page. We support three types of queries:

1. **Complete transfer:** Retrieve all records from an endpoint
2. **Batch primary key lookup:** We provide a list of primary keys, and you return all matching records
3. **Last modified datetime range lookup:** We provide a datetime range, and you return all records created or modified within that period

#### Querying Guidelines for Different Resources

* **User events** (e.g., Check-Ins, Sales): Last modified datetime range query.
* **Other resources** (e.g., User, Membership, Location): Support all three query types where applicable.

### Responses

* Responses should be UTF-8 encoded.
* All datetimes should be in ISO 8601 format with a UTC offset.

### Performance

Data related to user interactions (e.g., check-ins or purchases) should be available for consumption immediately upon occurrence.

## Redemption

To provide a more seamless experience for Perkville end-users, businesses often want to automate the distribution of redeemed rewards. This can be facilitated via POST endpoints that distribute dollar credits, service credits, coupons, etc.

### Customer IDs

Perkville stores an external member ID on a user's record. This allows us to see a transaction and then grab their corresponding customer ID, so that the reward, distributed via the API, can be associated with their account at the business.

### Location IDs

Similar to customer IDs, Perkville stores an external location ID. When a redemption transaction occurs, we're able to map to the correct location using this external location ID.

### Idempotent requests

Since the POST operations necessary to distribute a rewards are not naturally idempotent, there is risk for duplicate transactions. Perkville employs a number of strategies to ensure duplicate credits, for example, are not erroneously applied to an end-user's account. One such strategy is using the [voucher status](https://docs.perkville.com/features/redeeming-rules/custom-rewards/initial-voucher-status) to determine if the reward was distributed.

To ensure duplicates aren't created, it's helpful to include a unique ID in your API endpoint. If the same ID is passed into your API more than once, your API should reject duplicate requests. This gives both the business and Perkville team peace of mind when configuring automated reward distribution.

{% embed url="https://restfulapi.net/idempotent-rest-apis/" %}

### Integration Platform: Middle

We use our integration platform, [Middle](https://www.middle.app), to connect Perkville to various APIs. For more detailed guidelines on building an API for Middle, refer to [this guide](https://docs.middle.app/middle-docs/guides/building-an-api-for-middle).

{% embed url="https://docs.middle.app/middle-docs/" %}
