diff --git a/api.bs b/api.bs
index bbef101..e7cdf20 100644
--- a/api.bs
+++ b/api.bs
@@ -724,16 +724,47 @@ that "just tell me how to implement" goes in the API section. But I'd also be
fine with putting this in the DP section.
-->
-The privacy budget store records the state
-of the per-[=site=] [=privacy budgets=], and of any
-[=safety limits=]. It is updated by [=deduct privacy budget=].
+The [=privacy budget store=] records the state
+of the per-[=site=] [=privacy budgets=].
+It is updated by [=deduct privacy budget=].
-The [=privacy budget store=] needs to be described in more detail.
-Some references to clearing the impression store may need to be
-updated to refer to the privacy budget store as well.
+The [=safety limits=] need to be described in more detail.
+Some references to clearing
+the [=impression store=] may need to be
+updated to refer to the [=privacy budget store=] as well.
+A privacy budget key is a [=tuple=] consisting of the folowing items:
+
+
+: epoch
+:: A [=privacy budget epoch=]
+: site
+:: A [=site=]
+
+
+
+The privacy budget store is a [=map=] whose keys are
+[=privacy budget keys=] and whose values are [=floats=].
+
+To deduct privacy budget given a [=privacy budget key=] |key|,
+[=float=] |epsilon|, integer |sensitivity|, and integer |globalSensitivity|:
+
+1. If the [=privacy budget store=] does not [=map/contain=] |key|, [=map/set=]
+ its value of |key| to be a [=user-agent=]-defined value.
+
+1. Let |currentValue| be the result of [=map/get|getting the value=] of |key|
+ in the [=privacy budget store=].
+
+1. If |currentValue| is less than or equal to 0, return false.
+
+1. Let |newValue| be |currentValue| - |epsilon| * |sensitivity| / |globalSensitivity|.
+
+1. [=map/set|Set=] the value of |key| in the [=privacy budget store=] to |newValue|.
+
+1. Return whether |newValue| is greater than or equal to 0.
+
## Attribution Logic ## {#s-logic}
A site that measures conversions can specify attribution logic,
@@ -753,7 +784,8 @@ after the [=common matching logic=] is applied, and privacy budgeting occurs.
To do attribution and fill a histogram, given
- |options|:
+ |options| and
+ a [=site=] |topLevelSite|:
1. Initialize |matchedImpressions| to the empty [=set=].
@@ -767,8 +799,12 @@ To do attribution and fill a histogram, given
1. If |impressions| is not empty:
+ 1. Let |key| be a [=privacy budget key=] whose items are |epoch| and |topLevelSite|.
+
1. Let |budgetOk| be the result of [=deduct privacy budget=]
- with |epoch| and |options|.{{PrivateAttributionConversionOptions/epsilon}}.
+ with |key|, |options|.{{PrivateAttributionConversionOptions/epsilon}},
+ |options|.{{PrivateAttributionConversionOptions/value}},
+ and |options|.{{PrivateAttributionConversionOptions/maxValue}}.
1. If |budgetOk| is true, [=set/extend=] |matchedImpressions| with |impressions|.
@@ -1193,7 +1229,7 @@ changes that might occur days or weeks in the future.
## Privacy Budgets ## {#dp-budget}
-Browsers maintain a privacy budget,
+Browsers maintain privacy budgets,
which is a means of limiting the amount of privacy loss.
This specification uses an individual form
@@ -1219,7 +1255,7 @@ the budget for the [=privacy budget epoch=] in which those impressions were save
If the privacy budget for that [=privacy budget epoch|epoch=] is not sufficient,
the impressions from that [=privacy budget epoch|epoch=] are not used.
-The details of how to deduct privacy budget is given below ... WIP
+The details of how to [=deduct privacy budget=] is given below ... WIP
In the following figure,