Get Sales Tax Rate
Calculates the exact Ohio combined sales tax rate and statutory components for any jurisdiction within the state of Ohio.
Query Parameters
countystringqueryThe statutory Ohio county name or slug (e.g.
warren,franklin,cuyahoga). If provided, resolves immediately to that county's rate.
zipstringquery5-digit Ohio postal ZIP code (e.g.
43001or43003). Unambiguous ZIPs return the exact rate immediately. Ambiguous multi-county ZIPs return structured candidate counties or require theaddressparameter.
addressstringqueryFull delivery street address (e.g.
100 E Main St, Sunbury, OH 43003). Automatically geocoded via US Census Bureau boundaries to resolve split-county ZIPs with statutory precision.
datestringqueryEvaluation date in
YYYY-MM-DDISO format (defaults to current date). Used for historical audit calculations and future rate adjustments.
Code Examples
curl -X GET "https://app.ohiosalestaxcalculator.com/api/v1/rates?county=franklin" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
const res = await fetch("https://app.ohiosalestaxcalculator.com/api/v1/rates?county=franklin", {
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Accept": "application/json"
}
});
const rateData = await res.json();
console.log(`Franklin Rate: ${(rateData.combined_rate * 100).toFixed(2)}%`);
import requests
res = requests.get(
"https://app.ohiosalestaxcalculator.com/api/v1/rates",
params={"county": "franklin"},
headers={"Authorization": "Bearer YOUR_API_KEY"}
)
print(res.json())
Response: Exact Rate Match (200 OK)
countystringrequiredCanonical name of the Ohio county (e.g.
Warren,Franklin).
fipsstringrequired5-digit Ohio County FIPS code (e.g.
39165for Warren,39049for Franklin).
combined_ratenumberrequiredTotal statutory sales tax decimal rate (e.g.
0.08for 8.00%,0.0725for 7.25%).
componentsobjectrequiredRate Components
statenumber- Ohio State baseline rate (
0.0575/ 5.75%).
county_permissivenumber- County permissive tax rate (
0.0050-0.0150).
transit_authoritynumber- Regional transit authority levy (e.g. COTA
0.0100).
effective_fromstring | nullEffective date of the active rate (
YYYY-MM-DD).nullwhen the start date of the current rate is not recorded in our change history; treatnullas "in effect, start date unknown", not as an error.
transit_district_possiblebooleantruewhen the county is only partly inside a transit district (Delaware, Fairfield, Licking and Union: COTA; Wood: TARTA) and the request did not let us tell which side the location is on.combined_rateis then the countywide rate, and the rate inside the district istransit_district.combined_rate_inside(for example 8.25% in the COTA part of Licking County). Passaddressto resolve it. County and ZIP lookups in these counties always returntrue.
transit_districtobject | nullnullunless the county is split by a transit district. Fields:authority(COTAorTARTA),name,area,combined_rate_inside,status(inside,outsideorunknown), andnote. Foraddresslookups,statuscomes from the Census incorporated place returned for the address (for example Columbus, Dublin, Westerville or Reynoldsburg for COTA). When the address is inside, the levy is included incombined_rateandcomponents.transit_authority. A city annexation the Census has not yet recorded can be misclassified, so checkstatusfor addresses near a city line. Franklin County lies entirely within COTA, so its 1.00% COTA levy always appears incomponents.transit_authorityandtransit_districtisnull.
has_upcoming_changebooleantrueif an upcoming rate adjustment has been enacted by county commissioners with ODT.
resolved_bystringMethod used to resolve jurisdiction:
county_param,zip_unambiguous,address_geocoding, orzip_fallback.zip_fallbackmeans the Census geocoder could not match the street address (common for addresses like "1 Courthouse Square"), so the ZIP code from thezipparameter or the end of the address was used. If that ZIP spans several counties you get the ambiguous response instead. Include the ZIP in every address lookup so this fallback is available.
ambiguousbooleanAlways
falsefor exact matches.
statutory_sourcingstringLegal sourcing citation under Ohio R.C. § 5739.033.
request_idstringUnique request identifier for audit defense logging.
Response Example (200 OK)
{
"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",
"transit_district_possible": false,
"transit_district": null,
"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_8f12_90ab"
}
Response: Ambiguous Multi-County ZIP (200 OK)
When querying a split ZIP without a street address:
{
"ambiguous": true,
"zip": "43003",
"message": "ZIP code 43003 spans 2 Ohio counties (Delaware, Morrow). Provide the 'address' query parameter for exact address-level geocoding under Ohio R.C. 5739.033, or specify 'county'.",
"candidate_counties": [
{
"county": "Delaware",
"fips": "39041",
"combined_rate": 0.07,
"components": { "state": 0.0575, "county_permissive": 0.0125, "transit_authority": 0.0 },
"effective_from": null,
"transit_district_possible": true,
"transit_district": {
"authority": "COTA",
"name": "Central Ohio Transit Authority",
"area": "the parts of Columbus, Dublin and Westerville that cross the county line",
"combined_rate_inside": 0.08,
"status": "unknown",
"note": "Part of Delaware County is in the COTA district (the parts of Columbus, Dublin and Westerville that cross the county line), where the rate is 8.00%. combined_rate is the countywide rate; pass 'address' to resolve it."
}
},
{
"county": "Morrow",
"fips": "39117",
"combined_rate": 0.0725,
"components": { "state": 0.0575, "county_permissive": 0.015, "transit_authority": 0.0 },
"effective_from": null,
"transit_district_possible": false,
"transit_district": null
}
],
"date_evaluated": "2026-10-03",
"request_id": "req_1082_ef7c"
}
Error Responses (RFC 7807)
400 Bad Request
{
"type": "https://ohiosalestaxcalculator.com/errors/bad-request",
"title": "Invalid Parameters",
"status": 400,
"detail": "At least one of 'county', 'zip', or 'address' must be provided.",
"request_id": "req_err_400"
}
401 Unauthorized
{
"type": "https://ohiosalestaxcalculator.com/errors/unauthorized",
"title": "API Key Required",
"status": 401,
"detail": "A valid Bearer API key starting with 'ostx_' is required.",
"request_id": "req_err_401"
}
429 Too Many Requests
{
"type": "https://ohiosalestaxcalculator.com/errors/rate-limit-exceeded",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit of 10 requests per second exceeded. Please back off and retry.",
"request_id": "req_err_429"
}