Skip to content
Last updated

API Integration Workflow — Sales Data

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.

What you'll learn

  • 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

Prerequisites

  • A Green Check Access account with service provider credentials
  • Your client_id and client_secret from the developer portal
  • Basic familiarity with REST APIs and curl or an HTTP client

Step 1 — Authenticate

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"
}'
ParameterDescription
client_idYour unique client identifier from the developer portal
client_secretYour confidential client secret — never expose this in client-side code
grant_typeMust be client_credentials for server-to-server flows

💡 Tip — Token expiry

The response includes an expires_at timestamp. Check this value before each request and re-authenticate when the token is near expiry.


Step 2 — Retrieve connected CRBs

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_status field on each CRB before querying sales.


Step 3 — Fetch sales data

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 parameterDescription
start_dateStart of the date range (YYYY-MM-DD)
end_dateEnd of the date range (YYYY-MM-DD)
limitMaximum records to return per page (default: 1000, max: 1000)
offsetNumber of records to skip — use for pagination

Example response

{
  "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 query
  • limit — the page size used for this request
  • offset — the current starting position

💡 Tip — Pagination

If metadata.total exceeds your limit, increment offset by limit and repeat the request until you've retrieved all records. For example, to get page 2 of a 1000-record dataset with limit=100, set offset=100.


Error reference

StatusMeaningCommon cause & fix
401 UnauthorizedInvalid or missing tokenRe-authenticate with /auth/token and retry
403 ForbiddenInsufficient permissionsVerify your sp_id is correct and the CRB is connected to your org
404 Not FoundResource doesn't existDouble-check sp_id and crb_id UUIDs
422 Validation FailedInvalid parametersCheck 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-Remaining reaches zero:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window
X-RateLimit-RemainingRequests left in the current window
X-RateLimit-ResetUnix timestamp when the window resets

Complete Python example

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")

What's next