Quickstart Guide
This guide walks you through obtaining your API credentials and making your first live statutory tax rate lookup with the Ohio Sales Tax API.
Obtain your Secret API Key
Log into your Ohio Sales Tax Platform workspace:
- Navigate to API Keys & Webhooks.
- Click Create New API Key and provide a descriptive label (e.g.,
Production Shopify POS). - Copy your secret API key immediately:
ostx_live_9f8e7d6c5b4a3210...
Choose your Lookup Strategy
The API supports three lookup strategies depending on the data available at checkout:
Strategy Query Parameter Recommended Use Case County ?county=franklinOver-the-counter POS where the county is fixed. 5-Digit ZIP ?zip=43001Express checkout when only a ZIP code is known. Street Address ?address=100+E+Main+St...Deliveries and resolving ambiguous multi-county ZIPs. Send your First Rate Request
Execute a rate lookup for Franklin County (Columbus, OH):
cURL curl -X GET "https://app.ohiosalestaxcalculator.com/api/v1/rates?county=franklin" \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Accept: application/json"TypeScript / Node.js const API_KEY = process.env.OHIO_SALES_TAX_API_KEY!; async function getFranklinTaxRate() { const response = await fetch( "https://app.ohiosalestaxcalculator.com/api/v1/rates?county=franklin", { headers: { "Authorization": `Bearer ${API_KEY}`, "Accept": "application/json", }, } ); if (!response.ok) { throw new Error(`API error: ${response.status}`); } const data = await response.json(); console.log(`Franklin Combined Rate: ${(data.combined_rate * 100).toFixed(2)}%`); console.log("Levy Breakdown:", data.components); return data; }Python import os import requests api_key = os.environ.get("OHIO_SALES_TAX_API_KEY") response = requests.get( "https://app.ohiosalestaxcalculator.com/api/v1/rates", params={"county": "franklin"}, headers={"Authorization": f"Bearer {api_key}"} ) data = response.json() print(f"Franklin Combined Rate: {data['combined_rate'] * 100:.2f}%") print("Components:", data["components"])Go package main import ( "encoding/json" "fmt" "net/http" "os" ) type RateResponse struct { County string `json:"county"` CombinedRate float64 `json:"combined_rate"` Components struct { State float64 `json:"state"` CountyPermissive float64 `json:"county_permissive"` TransitAuthority float64 `json:"transit_authority"` } `json:"components"` } func main() { apiKey := os.Getenv("OHIO_SALES_TAX_API_KEY") req, _ := http.NewRequest("GET", "https://app.ohiosalestaxcalculator.com/api/v1/rates?county=franklin", nil) req.Header.Set("Authorization", "Bearer "+apiKey) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var result RateResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Franklin Combined Rate: %.2f%%\n", result.CombinedRate*100) }PHP <?php $apiKey = getenv('OHIO_SALES_TAX_API_KEY'); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://app.ohiosalestaxcalculator.com/api/v1/rates?county=franklin"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer " . $apiKey, "Accept: application/json" ]); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); echo "Franklin Combined Rate: " . ($data['combined_rate'] * 100) . "%\n"; ?>Inspect the Statutory Response
The API returns a statutory response containing the exact decimal rate and explicit levy components:
{ "county": "Franklin", "fips": "39049", "date_evaluated": "2026-10-03", "combined_rate": 0.08, "components": { "state": 0.0575, "county_permissive": 0.0125, "transit_authority": 0.01 }, "effective_from": "2025-04-01", "has_upcoming_change": false, "upcoming": null, "source": "Ohio Department of Taxation", "last_reconciled": "2026-10-01", "jurisdiction_type": "County Permissive", "statutory_sourcing": "Origin-Sourced under Ohio R.C. 5739.033(B)(1) for In-State Vendors", "resolved_by": "county_param", "ambiguous": false, "request_id": "req_88f91c_29a1" }
Handling Advanced Scenarios
1. Multi-County Split ZIP Codes
Over 530 ZIP codes in Ohio straddle county lines. When querying an ambiguous ZIP (e.g. 43003 which spans Delaware and Morrow counties):
curl -X GET "https://app.ohiosalestaxcalculator.com/api/v1/rates?zip=43003" \
-H "Authorization: Bearer YOUR_SECRET_KEY"
The API returns ambiguous: true along with candidate counties:
{
"zip": "43003",
"ambiguous": true,
"message": "ZIP 43003 spans multiple Ohio counties. Provide physical street address to resolve exact boundary.",
"candidate_counties": [
{ "county": "Delaware", "fips": "39041", "combined_rate": 0.07 },
{ "county": "Morrow", "fips": "39117", "combined_rate": 0.0725 }
],
"request_id": "req_split_43003"
}
To resolve this unambiguously, provide the street address:
curl -X GET "https://app.ohiosalestaxcalculator.com/api/v1/rates?address=100+E+Main+St,+Sunbury,+OH+43003" \
-H "Authorization: Bearer YOUR_SECRET_KEY"
2. Historical & Future Date Evaluation
Tax audits frequently require recalculating past transactions. Similarly, county commissioners announce rate adjustments months in advance. Pass the date parameter in YYYY-MM-DD ISO format:
# Evaluate historical rate for Cuyahoga County in 2023
curl -X GET "https://app.ohiosalestaxcalculator.com/api/v1/rates?county=cuyahoga&date=2023-06-15" \
-H "Authorization: Bearer YOUR_SECRET_KEY"