Phyzi partner integration
Phyzi turns a release into a physical product: a USB drive loaded with the album, its artwork and print art, duplicated, packed and shipped. These docs cover how a partner app delivers releases to us and orders drives for artists and fans.
You're reading the sandbox docs. Nothing you send to the sandbox is ever manufactured or shipped, and every slow real-world step can be triggered on demand (see Sandbox & testing).
How it fits together
| Step | You | Phyzi |
|---|---|---|
| 1. Deliver a release | Upload a DDEX ERN 4.3 batch to your S3 bucket | Validates it and sends release.validated or release.rejected |
| 2. Artist orders a master | POST /v1/master-orders |
Builds the master and runs production: proof → master built → units loaded → shipped |
| 3. Artist approves the proof | POST /v1/proofs/{id}/approve (or /reject) |
Continues production once approved |
| 4. Fan buys a drive | GET /v1/releases/{id}/availability, then POST /v1/fan-orders |
Ships it and sends fan_order.shipped with tracking |
You collect all payments from artists and fans. Phyzi invoices you wholesale. Never send card or payment details to Phyzi.
Environments
| Sandbox | Live | |
|---|---|---|
| API | https://dev.ddex-delivery.phyzi.io/v1 |
https://prod.ddex-delivery.phyzi.io/v1 (at go-live) |
| API keys | pk_test_… |
pk_live_… |
| Delivery bucket | s3://phyzi-ddex-aria-dev-750330851149 |
s3://phyzi-ddex-aria-prod-750330851149 |
| Region | us-east-2 |
us-east-2 |
The bucket credentials and your API key arrive separately, through a 1Password link.
Quickstart (about 15 minutes)
1. Check your key.
curl https://dev.ddex-delivery.phyzi.io/v1/me -H "Authorization: Bearer $PHYZI_KEY"
2. Register your webhook endpoint. The response includes your signing secret. Store it now,
because it's only shown once.
curl -X POST https://dev.ddex-delivery.phyzi.io/v1/webhook-endpoints \
-H "Authorization: Bearer $PHYZI_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://api.aria.example/webhooks/phyzi"}'
Then POST /v1/webhook-endpoints/{id}/test sends a signed ping event. Verify the signature.
3. Deliver a release. Either upload the sample package yourself:
unzip phyzi-sample-package.zip
aws s3 cp 20261101120000000/ s3://phyzi-ddex-aria-dev-750330851149/20261101120000000/ --recursive --exclude "BatchComplete_*"
aws s3 cp 20261101120000000/BatchComplete_20261101120000000.xml s3://phyzi-ddex-aria-dev-750330851149/20261101120000000/
…or have us drop it in for you with POST /v1/sandbox/deliveries/sample. Either way, within a
minute you'll get release.received and then release.validated, and GET /v1/releases/aria-rel-sample-0001 works.
4. Order a master, then walk it through production:
curl -X POST https://dev.ddex-delivery.phyzi.io/v1/master-orders \
-H "Authorization: Bearer $PHYZI_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"release_id": "aria-rel-sample-0001",
"external_id": "aria-order-123",
"artist": {"name": "Phyzi Sample Artist", "email": "artist@example.com"},
"units_to_stock": 50,
"units_to_artist": 10,
"packaging": "poly_bag",
"ship_to": {"name": "Phyzi Sample Artist", "line1": "1 Main St", "city": "Oklahoma City", "region": "OK", "postal_code": "73102", "country": "US"}
}'
Call POST /v1/sandbox/master-orders/{id}/advance to move it through each step and receive that
step's webhook. Approve the proof when master_order.proof_ready arrives. When it ships, the 50
stock units become available for fan orders.
5. Sell to fans. GET /v1/releases/aria-rel-sample-0001/availability, then POST /v1/fan-orders.
Call POST /v1/sandbox/fan-orders/{id}/ship to receive fan_order.shipped with a tracking number.
Conventions
- JSON everywhere, snake_case fields, ISO 8601 UTC timestamps.
- Your IDs are the keys. Releases are addressed by your release ID (the ERN
ProprietaryId). Orders take yourexternal_id, and a duplicateexternal_idis rejected with409. - Idempotency. Every POST that creates or changes an order needs an
Idempotency-Keyheader. Retrying with the same key and body returns the original response (headerIdempotent-Replayed: true). Reusing a key with a different body returns422. - Errors look like this:
{ "error": { "type": "conflict", "code": "out_of_stock", "message": "Only 0 units of aria-rel-sample-0001 in stock." } }
type is one of authentication_error (401), invalid_request_error (400), not_found (404),
conflict (409), idempotency_error (422) or api_error (500, safe to retry).
- Lists return
{ "object": "list", "data": [...], "has_more": false }, newest first, with?limit=(max 100).
Questions: email cooper@ivyokc.com.