diff --git a/tests/acceptance/Acceptance.csproj b/tests/acceptance/Acceptance.csproj
index a1f3232..c182441 100644
--- a/tests/acceptance/Acceptance.csproj
+++ b/tests/acceptance/Acceptance.csproj
@@ -11,6 +11,7 @@
+
diff --git a/tests/acceptance/Steps/EenZaakOpenenSteps.cs b/tests/acceptance/Steps/EenZaakOpenenSteps.cs
new file mode 100644
index 0000000..8c191bc
--- /dev/null
+++ b/tests/acceptance/Steps/EenZaakOpenenSteps.cs
@@ -0,0 +1,65 @@
+using Acceptance.Support;
+using Acl.Application;
+using Reqnroll;
+using Xunit;
+
+namespace Acceptance.Steps;
+
+/// Bindings for EenZaakOpenen.feature. Reqnroll creates one
+/// instance per scenario, so instance fields hold scenario-scoped state.
+[Binding]
+public sealed class EenZaakOpenenSteps
+{
+ private readonly InMemoryZaakGateway _gateway = new();
+ private DomainRegistration? _registration;
+ private AclDefaults? _defaults;
+ private DateOnly _today;
+ private Uri? _returnedUrl;
+
+ [Given("a domain registration for BSN \"(.*)\"")]
+ public void GivenADomainRegistrationForBsn(string bsn)
+ => _registration = new DomainRegistration(bsn);
+
+ [Given("the ACL is configured with these defaults:")]
+ public void GivenTheAclIsConfiguredWithTheseDefaults(DataTable defaults)
+ {
+ var values = ToFieldMap(defaults);
+ _defaults = new AclDefaults
+ {
+ Bronorganisatie = values["bronorganisatie"],
+ VerantwoordelijkeOrganisatie = values["verantwoordelijkeOrganisatie"],
+ Vertrouwelijkheidaanduiding = values["vertrouwelijkheidaanduiding"],
+ ZaaktypeUrl = new Uri(values["zaaktype"]),
+ };
+ }
+
+ [Given("today is \"(.*)\"")]
+ public void GivenTodayIs(string date)
+ => _today = DateOnly.Parse(date);
+
+ [When("the domain asks the ACL to open a zaak")]
+ public async Task WhenTheDomainAsksTheAclToOpenAZaak()
+ {
+ var service = new AclService(_gateway, _defaults!, new FixedClock(_today));
+ _returnedUrl = await service.OpenZaakAsync(_registration!);
+ }
+
+ [Then("a zaak is created with these default-filled fields")]
+ public void ThenAZaakIsCreatedWithTheseDefaultFilledFields(DataTable expected)
+ {
+ var request = Assert.IsType(_gateway.Captured);
+ var fields = ToFieldMap(expected);
+ Assert.Equal(fields["bronorganisatie"], request.Bronorganisatie);
+ Assert.Equal(fields["verantwoordelijkeOrganisatie"], request.VerantwoordelijkeOrganisatie);
+ Assert.Equal(fields["vertrouwelijkheidaanduiding"], request.Vertrouwelijkheidaanduiding);
+ Assert.Equal(fields["zaaktype"], request.Zaaktype.ToString());
+ Assert.Equal(fields["startdatum"], request.Startdatum.ToString("yyyy-MM-dd"));
+ }
+
+ [Then("the ACL returns the URL of the created zaak")]
+ public void ThenTheAclReturnsTheUrlOfTheCreatedZaak()
+ => Assert.Equal(InMemoryZaakGateway.CreatedZaakUrl, _returnedUrl);
+
+ private static Dictionary ToFieldMap(DataTable table)
+ => table.Rows.ToDictionary(r => r["field"], r => r["value"]);
+}
diff --git a/tests/acceptance/Support/FixedClock.cs b/tests/acceptance/Support/FixedClock.cs
new file mode 100644
index 0000000..b6d8dce
--- /dev/null
+++ b/tests/acceptance/Support/FixedClock.cs
@@ -0,0 +1,10 @@
+using Acl.Application;
+
+namespace Acceptance.Support;
+
+/// A clock pinned to a known date so startdatum is deterministic
+/// in scenarios (ADR-0003).
+public sealed class FixedClock(DateOnly today) : IClock
+{
+ public DateOnly Today { get; } = today;
+}
diff --git a/tests/acceptance/Support/InMemoryZaakGateway.cs b/tests/acceptance/Support/InMemoryZaakGateway.cs
new file mode 100644
index 0000000..a1dde7b
--- /dev/null
+++ b/tests/acceptance/Support/InMemoryZaakGateway.cs
@@ -0,0 +1,20 @@
+using Acl.Application;
+
+namespace Acceptance.Support;
+
+/// An in-memory stand-in for the OpenZaak Zaken API. It captures the
+/// fully default-filled the ACL builds and returns a
+/// fixed zaak URL, so the acceptance scenario can verify the use case without a
+/// running OpenZaak (real-OpenZaak verification is a separate slice).
+public sealed class InMemoryZaakGateway : IZaakGateway
+{
+ public static readonly Uri CreatedZaakUrl = new("http://openzaak/zaken/api/v1/zaken/created-123");
+
+ public ZaakRequest? Captured { get; private set; }
+
+ public Task OpenZaakAsync(ZaakRequest request, CancellationToken ct = default)
+ {
+ Captured = request;
+ return Task.FromResult(CreatedZaakUrl);
+ }
+}