1# ZDR with Private Safety Processing (PSP)
2
3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.
4
5li+li]:mt-2! [&_ul>li>p]:my-0! [&_#built-with-three-principles+ol>li+li]:mt-2! [&_#check-storage-status]:mt-0!">
6
7ZDR with PSP enables offline, automated safety review without OpenAI retaining customer prompts or responses. This guide provides an overview of how ZDR with PSP works and your operating responsibilities. For the full architecture and security model, see the [Private Safety Processing technical white paper](https://openaiassets.blob.core.windows.net/$web/pdf/c7284810-2252-462f-803e-075b0c95bccb/psp-whitepaper.pdf).
8
9## Built with Three Principles
10
111. **Customers control their content**
12
13 Customer content is stored in customer-controlled storage. Customers control the permissions and customer-managed Enterprise Key Management (EKM) authorization required to retrieve and decrypt protected safety records.
142. **No human review**
15
16 Safety review must not create a new way for OpenAI personnel to read protected customer content. Encrypted customer content is decrypted in an approved, hardware-attested safety runtime that disables human access. Only bounded safety signals and operational metadata leave the PSP protected review in plaintext.
173. **Content retention for safety only**
18
19 Content stored in customer-controlled storage serves only approved safety purposes. Customer content cannot be used to train models or be made available to other groups within OpenAI or its partners.
20
21## How ZDR with PSP Works
22
23The architecture consists of two flows:
24
25- The API Request and Retention flow protects and retains eligible API content in a customer-controlled storage container.
26- The Asynchronous Safety Pipeline retrieves records only for approved automated safety review and releases bounded safety decisions.
27
28### API Request and Retention
29
30An interaction - your prompt and the model’s response - is selected through a safety classifier referral or an approved sampling policy. A referral does not establish a policy violation.
31
32The system encrypts the record and writes it to your regional cloud storage. OpenAI keeps an index with operational metadata and a storage reference, not a copy of the content. Encryption and storage run asynchronously without blocking inference.
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53### Asynchronous Safety Pipeline
54
55ZDR with PSP retrieves encrypted records from your storage and checks their ability to be decrypted. The Safety Review Runtime, a hardware-attested computing environment that disables human access, is designed to be the only workload that can decrypt customer content. It performs automated safety review using an approved reviewer prompt and output schema that does not expose customer content.
56
57Only predefined, bounded safety signals and approved operational metadata may leave the review in plaintext. Detailed results are encrypted before leaving the runtime and stored in your cloud storage with the original record’s expiration. ZDR with PSP encrypts the records and writes them to your regional cloud storage with a TTL of 30 days.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75## Customer Content Encryption
76
77Each stored record is doubly encrypted when it is retained in customer storage:
78
79- **OpenAI-managed HPKE encryption:** The inner encryption layer restricts decryption of customer content to the authorized Safety Review Runtime.
80- **Customer-managed encryption:** [Enterprise Key Management (EKM)](https://help.openai.com/en/articles/20000943-openai-enterprise-key-management-ekm-overview) adds an outer layer using your customer-controlled key-management service.
81
82OpenAI’s inner decryption key is not enough to decrypt a stored record when EKM is enabled: your customer-managed key authorization is also required. Revoking that authorization prevents decryption of retained records, but does not delete them or undo completed processing.
83
84We recommend enabling EKM for this additional control. See the [EKM technical FAQ](https://help.openai.com/en/articles/20000945-ekm-technical-faq) for authorization and revocation, and the [technical whitepaper](https://openaiassets.blob.core.windows.net/$web/pdf/c7284810-2252-462f-803e-075b0c95bccb/psp-whitepaper.pdf) for encryption, confidential computing, guardrails, and transparency.
85
86
87
88<a id="customer-storage-setup-steps"></a>
89
90
91
92<a id="set-up-and-verify-customer-storage"></a>
93
94
95
96## Set Up and Verify Storage
97
98
99
100Connect your own AWS S3 bucket or Azure Blob container to an OpenAI project. Follow the setup steps for your cloud, then register and validate the connection.
101
102### Before you start
103
104- Ask your OpenAI contact to approve your organization.
105- Choose a storage region that matches your project's data residency. You need permission to create storage and delegate access in your cloud account.
106- Have an organization administrator register and validate storage in the API console. For the Management API, use an OpenAI organization Admin API key. Project administrators can view guidance and status; a project inference key won't work for the Management API calls.
107
108### Open storage setup in the API console
109
1101. Open **Organization settings > Data controls > Data retention**, then select **Connect storage**.
1112. In **Connect external storage**, choose **AWS** or **Azure** and select your project. You can also open **Connect storage** from **Project Settings > Data retention**.
1123. Complete the cloud setup below. Then enter your storage details in the modal and select **Connect and validate**.
113
114### Cloud-specific Setups
115
116
117
118<a id="aws-s3"></a>
119
120
121
122#### AWS S3
123
124
125
126Complete these steps if you're using AWS. For Azure, skip to **Azure Blob Storage**.
127
128#### 1. Create the bucket
129
130Create a dedicated S3 bucket in a region compatible with your project's data residency. If Data Residency is off, the recommended region is us-west-1.
131
132- Keep **ACLs disabled**.
133- Turn on **Block all Public Access**.
134- Record the bucket ARN. You'll use it as `CUSTOMER_BUCKET_ARN` below.
135
136
137
138#### 2. Set the lifecycle rule
139
140Open the bucket's **Management > Create lifecycle rule** page and use these settings:
141
142- **Rule name:** `psp-retention`
143- **Prefix:** `openai/`
144- **Action:** Expire current versions of objects
145- **Age:** 30 days
146
147Enable the rule. Make sure no other rule expires these records earlier. This sets the objects' lifecycle expiration; OpenAI's decryption-key expiration is separate.
148
149
150
151#### 3. Create the access policy
152
153In **IAM > Policies > Create policy**, choose **JSON**. Replace `CUSTOMER_BUCKET_ARN` with your bucket ARN, for example `arn:aws:s3:::your-psp-bucket`, and save the policy as `psp-bucket-policy`.
154
155```json
156{
157 "Version": "2012-10-17",
158 "Statement": [
159 {
160 "Effect": "Allow",
161 "Action": "s3:GetLifecycleConfiguration",
162 "Resource": "CUSTOMER_BUCKET_ARN"
163 },
164 {
165 "Effect": "Allow",
166 "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
167 "Resource": "CUSTOMER_BUCKET_ARN/*"
168 }
169 ]
170}
171```
172
173#### 4. Create the IAM role
174
175In **IAM > Roles > Create role**, choose **Custom trust policy**.
176
177
178
179Use the policy below. Replace `CUSTOMER_PROJECT_ID` with your OpenAI project ID. Leave the OpenAI principal ARN unchanged.
180
181```json
182{
183 "Version": "2012-10-17",
184 "Statement": [
185 {
186 "Effect": "Allow",
187 "Principal": {
188 "AWS": "arn:aws:iam::790389265272:role/CustomerStorage"
189 },
190 "Action": "sts:AssumeRole",
191 "Condition": {
192 "StringEquals": {
193 "sts:ExternalId": ["CUSTOMER_PROJECT_ID"]
194 }
195 }
196 }
197 ]
198}
199```
200
201Attach `psp-bucket-policy` to the role you are creating. You can name the role `psp-role`. Record its ARN as `CUSTOMER_ROLE_ARN`; the project ID in `sts:ExternalId` must match the project you register.
202
203
204
205Continue to **Register your storage**.
206
207
208
209
210
211
212
213<a id="azure-blob-storage"></a>
214
215
216
217#### Azure Blob Storage
218
219
220
221Complete these steps if you're using Azure.
222
223#### 1. Create the storage account
224
225Create a dedicated account in commercial Azure. Choose an approved US or EU storage region that matches your project's data residency.
226
227- **Account kind:** `StorageV2`
228- **Basics > Performance:** Standard
229- **Basics > Redundancy:** LRS or ZRS (preferred)
230- **Advanced > Access tier:** Hot
231- **Advanced > Hierarchical namespace:** Disabled
232- **Networking > Public network access:** Enabled from all networks
233- **Security > Secure transfer:** HTTPS required; minimum TLS 1.2
234- **Security > Anonymous Blob access:** Disabled
235- **Security > Storage account key access:** Disabled
236- **Security > Microsoft Entra Authorization:** Enabled
237
238Confirm the network setting meets your cloud requirements. Use the account's primary Blob endpoint, not a sovereign-cloud or custom endpoint.
239
240
241
242
243
244#### 2. Create the container
245
246Create a private container in **Storage Account > Data Storage > Containers > Add Container**. Add this container metadata in **Container > Settings > Metadata** with your exact OpenAI organization ID:
247
248- `openai_organization_id`: your OpenAI organization ID
249
250Add the metadata to the container, not the storage account or individual blobs.
251
252#### 3. Set the lifecycle rule
253
254Add an enabled rule in **Storage Account > Data Management > Lifecycle management > Add** that applies to all current/base block blobs in the dedicated account:
255
256- **Action:** Delete after 30 days since last modification
257- **Filters:** No prefix or tag filter
258
259
260
261
262
263#### 4. Grant OpenAI access
264
265Ask your directory administrator to add OpenAI's application to your tenant. Replace `CUSTOMER_TENANT_ID` below with your Azure tenant ID. Leave the application ID unchanged.
266
267```bash
268az login --tenant '<CUSTOMER_TENANT_ID>'
269az ad sp create --id 'e5627955-3059-4a88-89f8-73843190624d' \
270 --query '{name:displayName,objectId:id}' -o table
271```
272
273If the application already exists, use `az ad sp show` with the same `--id` and query. Record the application name and its tenant-local object ID.
274
275Open **Storage Account > Access control (IAM) > Add role assignment** on your storage account. Select the **Reader** role, set **Assign access to** to **User, group, or service principal**, then search for and select **CSG - Azure Blob Storage Prod**.
276
277
278
279
280
281Then select the **Storage Blob Data Contributor** role, set **Assign access to** to **User, group, or service principal**, and search for and select **CSG - Azure Blob Storage Prod**.
282
283OpenAI manages the application credentials. Don't create or share a storage key, SAS token, or client secret.
284
285
286
287
288
289### Register your storage
290
291After completing the cloud setup above, use either the API console or the Management API to register and validate your storage. You only need to use one method.
292
293#### Option 1: API console
294
295Sign in as an organization administrator. The API console uses your signed-in session; you don't need an Admin API key or curl commands for this method.
296
297##### 1. Open Connect storage
298
299Open **Organization settings > Data controls > Data retention** and select **Connect storage**. You can also connect from **Project Settings > Data retention**.
300
301
302
303##### 2. Enter your storage details
304
305Choose **AWS** or **Azure**, then select the project. If you opened the modal from project settings, that project is already selected. If **Registered storage** appears, choose **Connect new storage** to add a destination.
306
307For **AWS**, enter the **Bucket ARN** and **IAM role ARN** from your cloud setup.
308
309
310
311For **Azure**, enter **Tenant ID**, **Subscription ID**, **Resource group**, **Storage account name**, and **Container name**. Scroll down in the modal to complete all fields.
312
313
314
315##### 3. Connect and validate
316
317Select **Connect and validate**. The API console registers the storage, runs validation, and refreshes the storage status and project policy. Registration alone doesn't change the policy.
318
319Wait for **Storage validated** and confirmation that the project now uses ZDR with PSP, then select **Done**.
320
321
322
323If validation fails after registration, fix the reported issue and select **Retry validation**. To resume later, select the destination under **Registered storage** and choose **Validate storage**. If the API console can't refresh the result, select **Refresh status** before starting over.
324
325#### Option 2: Management API
326
327Use an organization Admin API key for this method. Register storage with the commands below, then follow [**3. Verify your setup**](#3-verify-your-setup) to run validation.
328
329##### 1. Prepare your API settings
330
331Load your organization Admin API key securely into `OPENAI_ADMIN_KEY`.
332
333Set `OPENAI_API_BASE` to the endpoint confirmed for your project: `https://api.openai.com` for global, `https://us.api.openai.com` for US, or `https://eu.api.openai.com` for Europe.
334
335Replace the placeholders below with that endpoint and your OpenAI organization ID. Run the remaining commands in the same shell session.
336
337```bash
338OPENAI_API_BASE='<OPENAI_API_BASE>'
339OPENAI_ORG_ID='<OPENAI_ORG_ID>'
340OPENAI_STORAGE_URL="$OPENAI_API_BASE/v1/organization/external_storage"
341```
342
343##### 2. Send the registration request
344
345Run the request for your provider only. Replace every `CUSTOMER_...` placeholder with your IDs and the resources you created.
346
347**AWS S3**
348
349```bash
350curl --fail-with-body -sS -X POST "$OPENAI_STORAGE_URL" \
351 -H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
352 -H "OpenAI-Organization: $OPENAI_ORG_ID" \
353 -H 'Content-Type: application/json' \
354 --data-binary '{
355 "project_id": "CUSTOMER_PROJECT_ID",
356 "provider": {
357 "type": "aws",
358 "bucket": "CUSTOMER_BUCKET_ARN",
359 "role_arn": "CUSTOMER_ROLE_ARN"
360 }
361 }'
362```
363
364**Azure Blob Storage**
365
366```bash
367curl --fail-with-body -sS -X POST "$OPENAI_STORAGE_URL" \
368 -H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
369 -H "OpenAI-Organization: $OPENAI_ORG_ID" \
370 -H 'Content-Type: application/json' \
371 --data-binary '{
372 "project_id": "CUSTOMER_PROJECT_ID",
373 "provider": {
374 "type": "azure",
375 "tenant_id": "CUSTOMER_TENANT_ID",
376 "subscription_id": "CUSTOMER_SUBSCRIPTION_ID",
377 "resource_group": "CUSTOMER_RESOURCE_GROUP",
378 "account_name": "CUSTOMER_STORAGE_ACCOUNT",
379 "container": "CUSTOMER_CONTAINER_NAME"
380 }
381 }'
382```
383
384The response contains an `id` beginning with `extstorage_` and `status: "pending"`. Keep the ID for validation. The API console shows **Pending validation** and leaves the project's retention policy unchanged.
385
386##### 3. Verify your setup
387
388For API validation, replace `EXTERNAL_STORAGE_ID` with the ID returned by registration, then run:
389
390```bash
391EXTERNAL_STORAGE_ID='<EXTERNAL_STORAGE_ID>'
392curl --fail-with-body -sS -X POST \
393 "$OPENAI_STORAGE_URL/$EXTERNAL_STORAGE_ID/validate" \
394 -H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
395 -H "OpenAI-Organization: $OPENAI_ORG_ID"
396```
397
398A successful response has `status: "validated"`. Validation checks configuration and access, then activates customer-managed retention for that project. The API console shows **Validated** and the read-only policy **Zero Data Retention with Private Safety Processing**.
399
400If you used the Management API, retrieve the saved registration:
401
402```bash
403curl --fail-with-body -sS \
404 "$OPENAI_STORAGE_URL/$EXTERNAL_STORAGE_ID" \
405 -H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
406 -H "OpenAI-Organization: $OPENAI_ORG_ID"
407```
408
409For either method, open **Project Settings > Data retention** and select **Refresh**. Confirm the destination, provider, geography, and **Validated** status, then check the policy is **Zero Data Retention with Private Safety Processing**. The organization Data retention table also shows storage and status for each project.
410
411
412
413**Validated** records a successful check, not continuous storage health. **Refresh** doesn't rerun validation. Use [Operations and Troubleshooting](#operate-and-troubleshoot-customer-storage) for ongoing monitoring and revalidation.
414
415
416
417
418
419
420
421<a id="customer-storage-operations-steps"></a>
422
423
424
425<a id="operate-and-troubleshoot-customer-storage"></a>
426
427
428
429## Troubleshooting
430
431
432
433### Check storage status
434
435Open **Organization settings > Data controls > Data retention** for the project table, or **Project Settings > Data retention** for the project's storage details. Check the destination and geography, then read the status. You can also retrieve the registration through the API in [Setup and Verification](#set-up-and-verify-customer-storage).
436
437- **Pending validation** (`pending`): Storage is registered but hasn't passed validation. The project's retention policy stays unchanged until validation succeeds.
438- **Validated** (`validated`): Storage passed a validation check. This doesn't guarantee live connectivity.
439- **Needs attention** (`unhealthy`): A check found a storage or configuration problem. Fix the cause and validate again.
440
441**Refresh** reloads saved status; it doesn't test the connection. A runtime failure may not change the displayed status. If the API console can't load storage, check the API before treating that as a bucket outage.
442
443### Monitor storage activity
444
445Check these sources separately:
446
447- **Storage registration:** Check the project, provider, geography, and validation result.
448- **Cloud activity:** Check provider access logs and read/write errors, where enabled. Separate validation probes from actual PSP activity.
449- **Safety and compliance events:** Check available content-lifecycle events in the Compliance API, if separately enabled. These aren't storage-registration events or cloud access logs.
450
451Your sampling policy determines which requests create retained objects. A missing object or event alone doesn't mean storage has failed.
452
453### Recover from a failure
454
455#### 1. Check the error
456
457- `customer_managed_retention_not_enabled`: Ask your onboarding contact to confirm organization access.
458- **Authentication or permission failure:** Check that you're using an organization Admin key with the required external-storage permission.
459- **Configuration problem:** Check the cloud identity, trust policy or access permissions, lifecycle rules, and approved network configuration.
460- `401 customer_storage_not_ready`: Check that validated storage exists for the requested project's geography.
461- `incorrect_hostname`: Use the hostname that matches your fixed-residency project's configuration.
462- `503 external_storage_validation_unavailable`: Retry later. Contact support if the failure persists.
463
464#### 2. Validate again
465
466After fixing the configuration, open **Connect storage** for the project and run the validation command with an organization Admin API key. Retrieve the registration or select **Refresh** to confirm **Validated**. Refresh alone doesn't run validation.
467
468### Contact support
469
470If storage or validation issues persist after troubleshooting, [contact OpenAI Support](https://help.openai.com/en/).
471
472### Change or stop your setup
473
474Contact support before replacing storage, revoking access, or offboarding. Complete setup and validation for each new project and residency location.
475
476Deleting a storage registration doesn't delete cloud objects or complete offboarding.
477
478
479
480
481
482## Ongoing Customer Responsibilities
483
484Customers using ZDR with PSP are required to:
485
486- **Register and validate PSP storage.** Register and validate storage buckets through OpenAI’s admin API for each PSP-enabled project and data-residency location, and configure PSP-service bucket access in accordance with OpenAI’s published guidance.
487- **Retain encrypted records for at least 30 days**. Configure storage lifecycle rules so they do not delete PSP records earlier.
488- **Maintain storage and key access**. Keep regional storage, service permissions, and customer-managed key authorization correctly configured.
489- **Repair configuration issues.** Correct storage configuration problems after OpenAI provides notification.
490- **Respond to notices about safety concerns.** Engage with OpenAI to investigate and address the concern.
491
492## Resources
493
494<ul>
495 <li>
496 [{"Private Safety Processing technical whitepaper"}](https://openaiassets.blob.core.windows.net/$web/pdf/c7284810-2252-462f-803e-075b0c95bccb/psp-whitepaper.pdf)
497 {" - Full architecture, security controls, and scope."}
498 </li>
499 <li>
500 [{"API data controls"}](https://developers.openai.com/api/docs/guides/your-data)
501 {" - ZDR eligibility, endpoint-specific retention, and exceptions."}
502 </li>
503 <li>
504 [{"Data residency"}](https://developers.openai.com/api/docs/guides/your-data#data-residency-controls)
505 {" - Supported regions and processing boundaries."}
506 </li>
507</ul>