Tutorial · Beginner · ⏱ ~20 min
This tutorial walks through a complete API integration workflow using Green Check Access: authenticate, retrieve the CRBs connected to your service provider, and pull sales data for a specific date range.
- Authenticate using OAuth 2.0 client credentials
- Retrieve all CRBs connected to your service provider account
- Fetch paginated sales data for a specific CRB and date range
- Handle common API errors and rate limits
- A Green Check Access account with service provider credentials
- Your
client_idandclient_secretfrom the developer portal - Basic familiarity with REST APIs and
curlor an HTTP client
All API requests require a Bearer token. Exchange your client credentials for an access token using the OAuth 2.0 client credentials flow.
curl --location 'https://sandbox-api.greencheckverified.com/auth/token' \
--header 'Content-Type: application/json' \
--data '{
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"grant_type": "client_credentials"
}'| Parameter | Description |
|---|---|
client_id | Your unique client identifier from the developer portal |
client_secret | Your confidential client secret — never expose this in client-side code |
grant_type | Must be client_credentials for server-to-server flows |
💡 Tip — Token expiry
The response includes an
expires_attimestamp. Check this value before each request and re-authenticate when the token is near expiry.
Fetch all CRBs associated with your service provider account. The response gives you the crb_id values you'll need to request sales data in Step 3.
curl --location 'https://sandbox-api.greencheckverified.com/service-providers/{sp_id}/crbs' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'Each CRB in the response includes:
- Business identification and contact details
- Integration status with connected POS systems
- Business type and operational information
- Due diligence status (
due_diligence_status)
ℹ️ Which CRBs have data?
Only CRBs with an active POS integration will have sales data available. Check the
pos_integration_statusfield on each CRB before querying sales.
With your sp_id and a crb_id from Step 2, request sales transactions for a specific date range.
curl --location 'https://sandbox-api.greencheckverified.com/service-providers/{sp_id}/crbs/{crb_id}/sales?start_date=2024-01-01&end_date=2024-01-31&limit=100' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'| Query parameter | Description |
|---|---|
start_date | Start of the date range (YYYY-MM-DD) |
end_date | End of the date range (YYYY-MM-DD) |
limit | Maximum records to return per page (default: 1000, max: 1000) |
offset | Number of records to skip — use for pagination |
{
"data": [
{
"id": "transaction-uuid",
"crb_id": "crb-uuid",
"date": "2024-01-15T14:30:00.000Z",
"local_date": "2024-01-15T07:30:00.000Z",
"subtotal": 4500,
"total_discounts": 500,
"tax_paid": 315,
"total_paid": 4315,
"transaction_type": "sale",
"pos_name": "Dutchie",
"line_items": [
{
"product_name": "Blue Dream - 1g Flower",
"num_units": 1,
"price_per_unit": 4500,
"grams": 1,
"product_type": "flower",
"cannabis_product": true
}
]
}
],
"metadata": {
"total": 1250,
"limit": 100,
"offset": 0
}
}The metadata object tells you how to paginate through the full result set:
total— total number of records matching your querylimit— the page size used for this requestoffset— the current starting position
💡 Tip — Pagination
If
metadata.totalexceeds yourlimit, incrementoffsetbylimitand repeat the request until you've retrieved all records. For example, to get page 2 of a 1000-record dataset withlimit=100, setoffset=100.
| Status | Meaning | Common cause & fix |
|---|---|---|
401 Unauthorized | Invalid or missing token | Re-authenticate with /auth/token and retry |
403 Forbidden | Insufficient permissions | Verify your sp_id is correct and the CRB is connected to your org |
404 Not Found | Resource doesn't exist | Double-check sp_id and crb_id UUIDs |
422 Validation Failed | Invalid parameters | Check date format (YYYY-MM-DD) and other query parameters against the API reference |
⚠️ Rate limiting
The API enforces rate limits. Monitor these response headers and back off when
X-RateLimit-Remainingreaches zero:
Header Description X-RateLimit-LimitMaximum requests allowed per window X-RateLimit-RemainingRequests left in the current window X-RateLimit-ResetUnix timestamp when the window resets
The snippet below brings all three steps together using the requests library, including a paginated fetch that handles result sets larger than a single page.
import requests
from datetime import datetime, timedelta
class GreenCheckClient:
def __init__(self, client_id, client_secret,
base_url="https://sandbox-api.greencheckverified.com"):
self.client_id = client_id
self.client_secret = client_secret
self.base_url = base_url
self.token = None
def authenticate(self):
"""Exchange credentials for a bearer token."""
response = requests.post(f"{self.base_url}/auth/token", json={
"client_id": self.client_id,
"client_secret": self.client_secret,
"grant_type": "client_credentials",
})
response.raise_for_status()
self.token = response.json()["access_token"]
def get_crbs(self, sp_id):
"""Return all CRBs connected to your service provider."""
headers = {"Authorization": f"Bearer {self.token}"}
response = requests.get(
f"{self.base_url}/service-providers/{sp_id}/crbs",
headers=headers,
)
response.raise_for_status()
return response.json()
def get_sales(self, sp_id, crb_id, start_date, end_date, limit=100):
"""Fetch all sales records for a CRB across a date range, paginating as needed."""
headers = {"Authorization": f"Bearer {self.token}"}
all_records = []
offset = 0
while True:
response = requests.get(
f"{self.base_url}/service-providers/{sp_id}/crbs/{crb_id}/sales",
headers=headers,
params={
"start_date": start_date,
"end_date": end_date,
"limit": limit,
"offset": offset,
},
)
response.raise_for_status()
payload = response.json()
all_records.extend(payload["data"])
if offset + limit >= payload["metadata"]["total"]:
break
offset += limit
return all_records
# Usage
client = GreenCheckClient("your-client-id", "your-client-secret")
client.authenticate()
sp_id = "your-sp-id"
crb_id = "target-crb-id"
end_date = datetime.now().date()
start_date = end_date - timedelta(days=30)
crbs = client.get_crbs(sp_id)
print(f"Found {len(crbs)} connected CRBs")
sales = client.get_sales(sp_id, crb_id, start_date, end_date)
print(f"Retrieved {len(sales)} sales transactions")- Integration overview — understand all four core integration patterns end to end
- CRB onboarding templates — fetch submitted application data and documents for a CRB
- Integration status — see which POS systems expose which data types
- API reference — full schema and endpoint documentation