diff --git a/CHANGES b/CHANGES
index 3fcb802..d7154d0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,9 @@
-Next
-----
+0.11.0 (Soon)
+-------------
 - Require boto3>=1.4 to get `upload_fileobj()`.
 - Add a callback function for AWS SDK uploads to `uploads.stage()` (#147).
+- Allow configuration of API host using MAPBOX_HOST environment variable or
+  Service constructor keyword argument `host` (#143, #150).
 
 0.10.1 (2016-11-22)
 -------------------
diff --git a/mapbox/services/base.py b/mapbox/services/base.py
index 6b66533..421565e 100644
--- a/mapbox/services/base.py
+++ b/mapbox/services/base.py
@@ -32,13 +32,16 @@ def Session(access_token=None, env=os.environ):
 class Service(object):
     """Service base class."""
 
-    def __init__(self, access_token=None, cache=None):
+    default_host = 'api.mapbox.com'
+
+    def __init__(self, access_token=None, host=None, cache=None):
         """Constructs a Service object.
 
         :param access_token: Mapbox access token string.
         :param cache: CacheControl cache instance (Dict or FileCache).
         """
         self.session = Session(access_token)
+        self.host = host or os.environ.get('MAPBOX_HOST', self.default_host)
         if cache:
             self.session = CacheControl(self.session, cache=cache)
 
diff --git a/mapbox/services/datasets.py b/mapbox/services/datasets.py
index c913fc3..921897b 100644
--- a/mapbox/services/datasets.py
+++ b/mapbox/services/datasets.py
@@ -7,14 +7,12 @@ from uritemplate import URITemplate
 from mapbox.services.base import Service
 
 
-# Constants
-BASE_URI = 'https://api.mapbox.com/datasets/v1'
-
-
 class Datasets(Service):
     """Access to the Datasets API."""
 
-    baseuri = 'https://api.mapbox.com/datasets/v1'
+    @property
+    def baseuri(self):
+        return 'https://{0}/datasets/v1'.format(self.host)
 
     def _attribs(self, name=None, description=None):
         """Form an attributes dictionary from keyword args."""
@@ -94,7 +92,8 @@ class Datasets(Service):
         :param dataset: the dataset identifier string.
         """
         uri = URITemplate(self.baseuri + '/{owner}/{id}/features').expand(
-                owner=self.username, id=dataset)
+            owner=self.username, id=dataset)
+
         params = {}
         if reverse:
             params['reverse'] = 'true'
diff --git a/mapbox/services/directions.py b/mapbox/services/directions.py
index 9b6ba52..d6f6af3 100644
--- a/mapbox/services/directions.py
+++ b/mapbox/services/directions.py
@@ -8,13 +8,16 @@ from mapbox import errors
 class Directions(Service):
     """Access to the Directions API."""
 
-    baseuri = 'https://api.mapbox.com/v4/directions'
     valid_profiles = ['mapbox.driving',
                       'mapbox.cycling',
                       'mapbox.walking']
     valid_instruction_formats = ['text', 'html']
     valid_geom_encoding = ['geojson', 'polyline', 'false']
 
+    @property
+    def baseuri(self):
+        return 'https://{0}/v4/directions'.format(self.host)
+
     def _validate_profile(self, profile):
         if profile not in self.valid_profiles:
             raise errors.InvalidProfileError(
diff --git a/mapbox/services/distance.py b/mapbox/services/distance.py
index 7b89121..be27a34 100644
--- a/mapbox/services/distance.py
+++ b/mapbox/services/distance.py
@@ -8,9 +8,12 @@ from mapbox.services.base import Service
 class Distance(Service):
     """Access to the Distance API."""
 
-    baseuri = 'https://api.mapbox.com/distances/v1/mapbox'
     valid_profiles = ['driving', 'cycling', 'walking']
 
+    @property
+    def baseuri(self):
+        return 'https://{0}/distances/v1/mapbox'.format(self.host)
+
     def _validate_profile(self, profile):
         if profile not in self.valid_profiles:
             raise InvalidProfileError(
diff --git a/mapbox/services/geocoding.py b/mapbox/services/geocoding.py
index 8c66aba..85c03c7 100644
--- a/mapbox/services/geocoding.py
+++ b/mapbox/services/geocoding.py
@@ -9,9 +9,12 @@ from mapbox.services.base import Service
 class Geocoder(Service):
     """Access to the Geocoding API."""
 
-    baseuri = 'https://api.mapbox.com/geocoding/v5'
     precision = {'reverse': 5, 'proximity': 3}
 
+    @property
+    def baseuri(self):
+        return 'https://{0}/geocoding/v5'.format(self.host)
+
     def __init__(self, name='mapbox.places', access_token=None, cache=None):
         """Constructs a Geocoding Service object.
 
diff --git a/mapbox/services/mapmatching.py b/mapbox/services/mapmatching.py
index 6a68b96..cec6acc 100644
--- a/mapbox/services/mapmatching.py
+++ b/mapbox/services/mapmatching.py
@@ -9,9 +9,12 @@ from mapbox.services.base import Service
 class MapMatcher(Service):
     """Access to the Map Matching API."""
 
-    baseuri = 'https://api.mapbox.com/matching/v4'
     valid_profiles = ['mapbox.driving', 'mapbox.cycling', 'mapbox.walking']
 
+    @property
+    def baseuri(self):
+        return 'https://{0}/matching/v4'.format(self.host)
+
     def _validate_profile(self, profile):
         if profile not in self.valid_profiles:
             raise errors.InvalidProfileError(
diff --git a/mapbox/services/static.py b/mapbox/services/static.py
index 5f81a88..fe5a9fb 100644
--- a/mapbox/services/static.py
+++ b/mapbox/services/static.py
@@ -10,7 +10,9 @@ from mapbox.utils import normalize_geojson_featurecollection
 class Static(Service):
     """Access to the Static Map API."""
 
-    baseuri = 'https://api.mapbox.com/v4'
+    @property
+    def baseuri(self):
+        return 'https://{0}/v4'.format(self.host)
 
     def _validate_lat(self, val):
         if val < -85.0511 or val > 85.0511:
diff --git a/mapbox/services/surface.py b/mapbox/services/surface.py
index aabbc18..8c69073 100644
--- a/mapbox/services/surface.py
+++ b/mapbox/services/surface.py
@@ -7,7 +7,9 @@ from mapbox.services.base import Service
 class Surface(Service):
     """Access to the Surface API."""
 
-    baseuri = 'https://api.mapbox.com/v4/surface'
+    @property
+    def baseuri(self):
+        return 'https://{0}/v4/surface'.format(self.host)
 
     def surface(self,
                 features,
diff --git a/mapbox/services/uploads.py b/mapbox/services/uploads.py
index 3e765a0..1fe1f2f 100644
--- a/mapbox/services/uploads.py
+++ b/mapbox/services/uploads.py
@@ -27,7 +27,9 @@ class Uploader(Service):
         assert job not in u.list().json()
     """
 
-    baseuri = 'https://api.mapbox.com/uploads/v1'
+    @property
+    def baseuri(self):
+        return 'https://{0}/uploads/v1'.format(self.host)
 
     def _get_credentials(self):
         """Gets temporary S3 credentials to stage user-uploaded files
diff --git a/mapbox/utils.py b/mapbox/utils.py
index b811212..ad53c69 100644
--- a/mapbox/utils.py
+++ b/mapbox/utils.py
@@ -1,5 +1,6 @@
 from collections import Mapping, Sequence
 
+
 def normalize_geojson_featurecollection(obj):
     """Takes a geojson-like mapping representing
     geometry, Feature or FeatureCollection (or a sequence of such objects)

Configurable baseuri
Currently, the endpoint for all services is hardcoded for each service as `baseuri`

```
mapbox/services/datasets.py:    baseuri = 'https://api.mapbox.com/datasets/v1'
mapbox/services/directions.py:    baseuri = 'https://api.mapbox.com/v4/directions'
mapbox/services/distance.py:    baseuri = 'https://api.mapbox.com/distances/v1/mapbox'
mapbox/services/geocoding.py:    baseuri = 'https://api.mapbox.com/geocoding/v5'
mapbox/services/mapmatching.py:    baseuri = 'https://api.mapbox.com/matching/v4'
mapbox/services/static.py:    baseuri = 'https://api.mapbox.com/v4'
mapbox/services/surface.py:    baseuri = 'https://api.mapbox.com/v4/surface'
mapbox/services/uploads.py:    baseuri = 'https://api.mapbox.com/uploads/v1'
```

There is a need for changing this in order to hit staging/testing endpoints that implement the same services. Ideally we'd have a true base URI (defaulting to `https://api.mapbox.com/`) that was easily configurable from any service class. Something like...

```
>>> service = mapbox.Upload()
>>> service.base = 'http://my-local-test-server/'
>>> service.baseuri
http://my-local-test-server/uploads/v1
```

Are there other mechanisms for changing the base uri? What about environment variables?

We'll also want to plan the corresponding flags in the command line interface.
diff --git a/tests/test_base.py b/tests/test_base.py
index 24f2b57..2025043 100644
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -85,6 +85,17 @@ def test_username(monkeypatch):
     assert service.username == 'testuser'
 
 
+def test_default_host():
+    service = base.Service()
+    assert service.host == 'api.mapbox.com'
+
+
+def test_configured_host(monkeypatch):
+    monkeypatch.setenv('MAPBOX_HOST', 'example.com')
+    service = base.Service()
+    assert service.host == 'example.com'
+
+
 def test_username_failures(monkeypatch):
     monkeypatch.delenv('MAPBOX_ACCESS_TOKEN', raising=False)
     monkeypatch.delenv('MapboxAccessToken', raising=False)

pip install -e .[test]
parse_log_pytest
pytest
pytest
3.5
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
boto3==1.23.10
botocore==1.26.10
CacheControl==0.12.14
certifi==2021.5.30
charset-normalizer==2.0.12
click==8.0.4
click-plugins==1.1.1
cligj==0.7.2
coverage==6.2
coveralls==3.3.1
distlib==0.3.9
docopt==0.6.2
filelock==3.4.1
idna==3.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
iso3166==2.1.1
jmespath==0.10.0
-e git+https://github.com/mapbox/mapbox-sdk-py.git@1481f35d31bf102a2affe97073694ae16e0c40a8#egg=mapbox
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
msgpack==1.0.5
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
platformdirs==2.4.0
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
polyline==1.4.0
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
pytest-cov==4.0.0
python-dateutil==2.9.0.post0
requests==2.27.1
responses==0.17.0
s3transfer==0.5.2
six==1.17.0
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
tomli==1.2.3
tox==3.28.0
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
uritemplate==4.1.1
urllib3==1.26.20
virtualenv==20.17.1
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: mapbox-sdk-py
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - boto3==1.23.10
      - botocore==1.26.10
      - cachecontrol==0.12.14
      - charset-normalizer==2.0.12
      - click==8.0.4
      - click-plugins==1.1.1
      - cligj==0.7.2
      - coverage==6.2
      - coveralls==3.3.1
      - distlib==0.3.9
      - docopt==0.6.2
      - filelock==3.4.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iso3166==2.1.1
      - jmespath==0.10.0
      - msgpack==1.0.5
      - platformdirs==2.4.0
      - polyline==1.4.0
      - pytest-cov==4.0.0
      - python-dateutil==2.9.0.post0
      - requests==2.27.1
      - responses==0.17.0
      - s3transfer==0.5.2
      - six==1.17.0
      - tomli==1.2.3
      - tox==3.28.0
      - uritemplate==4.1.1
      - urllib3==1.26.20
      - virtualenv==20.17.1
prefix: /opt/conda/envs/mapbox-sdk-py

tests/test_base.py::test_default_host tests/test_base.py::test_configured_host
tests/test_base.py::test_service_session tests/test_base.py::test_service_session_env tests/test_base.py::test_service_session_os_environ tests/test_base.py::test_service_session_os_environ_caps tests/test_base.py::test_service_session_os_environ_precedence tests/test_base.py::test_user_agent tests/test_base.py::test_custom_messages tests/test_base.py::test_username tests/test_base.py::test_username_failures
mapbox/services/base.py mapbox/services/distance.py mapbox/services/directions.py mapbox/services/surface.py mapbox/services/geocoding.py mapbox/services/datasets.py CHANGES mapbox/utils.py mapbox/services/mapmatching.py mapbox/services/static.py mapbox/services/uploads.py
mapbox/services/base.py mapbox/services/distance.py mapbox/services/directions.py mapbox/services/surface.py mapbox/services/geocoding.py mapbox/services/datasets.py CHANGES mapbox/utils.py mapbox/services/mapmatching.py mapbox/services/static.py mapbox/services/uploads.py