grayside: I have not read into the spec sufficiently to evaluate this requirement.
diff --git a/cloudevents/sdk/event/base.py b/cloudevents/sdk/event/base.py
index 791eb67..2004dbb 100644
--- a/cloudevents/sdk/event/base.py
+++ b/cloudevents/sdk/event/base.py
@@ -201,6 +201,9 @@ class BaseEvent(EventGetterSetter):
                 props["data_base64"] = base64.b64encode(data).decode("ascii")
             else:
                 props["data"] = data
+        if "extensions" in props:
+            extensions = props.pop("extensions")
+            props.update(extensions)
         return json.dumps(props)
 
     def UnmarshalJSON(

Structured extensions aren't serialized top level in to_http result
## Actual Behavior
```python
from cloudevents.sdk.http_events import CloudEvent
attributes = {"source": "<source-url>", "type": "com.issue.extensions", "example-extension": "ext1"}
data = 'Hello'
event = CloudEvent(attributes, data)
headers, body = event.to_http()
print(body)
```

The above code will produce the following:

```
b'{"specversion": "1.0", "id": "fc713795-93f6-44a8-b67e-7b8bd7071e2a", "source": "<source-url>", "type": "com.issue.extensions", "time": "2020-07-16T22:41:48.222788+00:00", "extensions": {"example-extension": "ext1"}, "data": "Hello"}'
```

When in fact we expectthis to be outputted:
```
b'{"specversion": "1.0", "id": "fc713795-93f6-44a8-b67e-7b8bd7071e2a", "source": "<source-url>", "type": "com.issue.extensions", "time": "2020-07-16T22:41:48.222788+00:00", "example-extension": "ext1", "data": "Hello"}'
```

Current output is readable by python CloudEvents, but possibly not by other cloudevent systems unless I'm misunderstanding extensions. 
diff --git a/cloudevents/tests/test_event_extensions.py b/cloudevents/tests/test_event_extensions.py
new file mode 100644
index 0000000..57afff4
--- /dev/null
+++ b/cloudevents/tests/test_event_extensions.py
@@ -0,0 +1,92 @@
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+import json
+
+import pytest
+
+from cloudevents.sdk.http import (
+    CloudEvent,
+    from_http,
+    to_binary_http,
+    to_structured_http,
+)
+
+test_data = json.dumps({"data-key": "val"})
+test_attributes = {
+    "type": "com.example.string",
+    "source": "https://example.com/event-producer",
+    "ext1": "testval",
+}
+
+
+@pytest.mark.parametrize("specversion", ["0.3", "1.0"])
+def test_cloudevent_access_extensions(specversion):
+    event = CloudEvent(test_attributes, test_data)
+    assert event["ext1"] == "testval"
+
+
+@pytest.mark.parametrize("specversion", ["0.3", "1.0"])
+def test_to_binary_extensions(specversion):
+    event = CloudEvent(test_attributes, test_data)
+    headers, body = to_binary_http(event)
+
+    assert "ce-ext1" in headers
+    assert headers.get("ce-ext1") == test_attributes["ext1"]
+
+
+@pytest.mark.parametrize("specversion", ["0.3", "1.0"])
+def test_from_binary_extensions(specversion):
+    headers = {
+        "ce-id": "1234",
+        "ce-source": "<my url>",
+        "ce-type": "sample",
+        "ce-specversion": specversion,
+        "ce-ext1": "test1",
+        "ce-ext2": "test2",
+    }
+    body = json.dumps({"data-key": "val"})
+    event = from_http(body, headers)
+
+    assert headers["ce-ext1"] == event["ext1"]
+    assert headers["ce-ext2"] == event["ext2"]
+
+
+@pytest.mark.parametrize("specversion", ["0.3", "1.0"])
+def test_to_structured_extensions(specversion):
+    event = CloudEvent(test_attributes, test_data)
+    headers, body = to_structured_http(event)
+
+    body = json.loads(body)
+
+    assert "ext1" in body
+    assert "extensions" not in body
+
+
+@pytest.mark.parametrize("specversion", ["0.3", "1.0"])
+def test_from_structured_extensions(specversion):
+    headers = {"Content-Type": "application/cloudevents+json"}
+    body = {
+        "id": "1234",
+        "source": "<my url>",
+        "type": "sample",
+        "specversion": specversion,
+        "ext1": "test1",
+        "ext2": "test2",
+    }
+
+    data = json.dumps(body)
+    event = from_http(data, headers)
+
+    assert body["ext1"] == event["ext1"]
+    assert body["ext2"] == event["ext2"]
diff --git a/requirements/test.txt b/requirements/test.txt
index 4c9fb75..1d5f308 100644
--- a/requirements/test.txt
+++ b/requirements/test.txt
@@ -9,3 +9,5 @@ pytest-cov==2.4.0
 sanic
 aiohttp
 Pillow
+requests
+

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
3.8
requirements/test.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aiofiles==24.1.0
aiohappyeyeballs==2.4.4
aiohttp==3.10.11
aiosignal==1.3.1
async-timeout==5.0.1
atomicwrites==1.4.1
attrs==25.3.0
black==24.8.0
click==8.1.8
-e git+https://github.com/cloudevents/sdk-python.git@0aa01ba5c6eb9c2bc6a583104068a87ca9d66708#egg=cloudevents
coverage==7.6.1
enum-compat==0.0.3
exceptiongroup==1.2.2
execnet==2.1.1
flake8==7.1.2
flake8-import-order==0.18.2
flake8-polyfill==1.0.2
flake8-print==5.0.0
flake8-strict==0.2.1
frozenlist==1.5.0
html5tagger==1.3.0
httptools==0.6.4
idna==3.10
iniconfig==2.1.0
mccabe==0.7.0
more-itertools==10.5.0
multidict==6.1.0
mypy-extensions==1.0.0
packaging==24.2
pathspec==0.12.1
pep8-naming==0.5.0
pillow==10.4.0
platformdirs==4.3.6
pluggy==1.5.0
propcache==0.2.0
py==1.11.0
pycodestyle==2.12.1
pyflakes==3.2.0
pytest==8.3.5
pytest-asyncio==0.24.0
pytest-cov==2.4.0
pytest-mock==3.14.0
pytest-xdist==3.6.1
sanic==24.12.0
sanic-routing==23.12.0
six==1.17.0
tomli==2.2.1
tracerite==1.1.1
typing_extensions==4.13.0
ujson==5.10.0
uvloop==0.21.0
websockets==13.1
yarl==1.15.2

name: sdk-python
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
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=24.2=py38h06a4308_0
  - python=3.8.20=he870216_0
  - readline=8.2=h5eee18b_0
  - setuptools=75.1.0=py38h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.44.0=py38h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aiofiles==24.1.0
      - aiohappyeyeballs==2.4.4
      - aiohttp==3.10.11
      - aiosignal==1.3.1
      - async-timeout==5.0.1
      - atomicwrites==1.4.1
      - attrs==25.3.0
      - black==24.8.0
      - click==8.1.8
      - cloudevents==0.3.1.dev14
      - coverage==7.6.1
      - enum-compat==0.0.3
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - flake8==7.1.2
      - flake8-import-order==0.18.2
      - flake8-polyfill==1.0.2
      - flake8-print==5.0.0
      - flake8-strict==0.2.1
      - frozenlist==1.5.0
      - html5tagger==1.3.0
      - httptools==0.6.4
      - idna==3.10
      - iniconfig==2.1.0
      - mccabe==0.7.0
      - more-itertools==10.5.0
      - multidict==6.1.0
      - mypy-extensions==1.0.0
      - packaging==24.2
      - pathspec==0.12.1
      - pep8-naming==0.5.0
      - pillow==10.4.0
      - platformdirs==4.3.6
      - pluggy==1.5.0
      - propcache==0.2.0
      - py==1.11.0
      - pycodestyle==2.12.1
      - pyflakes==3.2.0
      - pytest==8.3.5
      - pytest-asyncio==0.24.0
      - pytest-cov==2.4.0
      - pytest-mock==3.14.0
      - pytest-xdist==3.6.1
      - sanic==24.12.0
      - sanic-routing==23.12.0
      - six==1.17.0
      - tomli==2.2.1
      - tracerite==1.1.1
      - typing-extensions==4.13.0
      - ujson==5.10.0
      - uvloop==0.21.0
      - websockets==13.1
      - yarl==1.15.2
prefix: /opt/conda/envs/sdk-python

cloudevents/tests/test_event_extensions.py::test_to_structured_extensions[0.3] cloudevents/tests/test_event_extensions.py::test_to_structured_extensions[1.0]
cloudevents/tests/test_event_extensions.py::test_cloudevent_access_extensions[0.3] cloudevents/tests/test_event_extensions.py::test_cloudevent_access_extensions[1.0] cloudevents/tests/test_event_extensions.py::test_to_binary_extensions[0.3] cloudevents/tests/test_event_extensions.py::test_to_binary_extensions[1.0] cloudevents/tests/test_event_extensions.py::test_from_binary_extensions[0.3] cloudevents/tests/test_event_extensions.py::test_from_binary_extensions[1.0] cloudevents/tests/test_event_extensions.py::test_from_structured_extensions[0.3] cloudevents/tests/test_event_extensions.py::test_from_structured_extensions[1.0]
cloudevents/sdk/event/base.py
cloudevents/sdk/event/base.py