Returns (Phase 3 preview)
Implementation-ready Phase 3 preview for signed return requests, operator review, authoritative routing, idempotent return creation and controlled activation.
Phase 3 contract — implementation-ready preview. The wire contract is
frozen and the SKUU-side receiver, review/routing storage and signed customer
client are implemented and locally proven, including the durable operator
release/resume path. The shared TESTING schema/runtime foundation is installed,
read back and empty, while the receiver, outbound creation and recurring sender
remain disabled. A customer must still implement the two interfaces in this
guide and pass bilateral TESTING conformance before either side enables return
traffic. This is not a customer-traffic or production activation notice.
This guide adds returns to the product, inventory, order and fulfilment
integration. Complete Phases 1 and 2 before implementing these interfaces.
This page is the complete public Phase-3 preview contract. The API Reference
in this portal remains the machine-readable contract for accepted Phase 1 and
Phase 2 endpoints until Phase 3 bilateral acceptance.
Overview
| Connection | Direction | Purpose |
|---|---|---|
return.created webhook | Customer → SKUU | Submit one consumer return request for one original consumer order |
POST /returns | SKUU → customer | Create one operator-approved return at the original seller for one seller order and physical fulfilment location |
Phase 3 reuses the existing environment credentials:
- customer-to-SKUU webhooks use the shared HMAC secret;
- SKUU-to-customer requests use the customer-issued bearer token and the same
shared HMAC secret; and - TESTING and production use separate URLs and credentials.
SKUU's safe defaults are returns.receiver_enabled=false,
returns.creation_enabled=false, and returns.creation_dry_run=true. Code
presence does not enable a customer, environment, receiver, outbound write,
recurring sender or production.
What the customer implements
Before bilateral conformance, the customer prepares exactly two capabilities:
- emit a signed
return.createdevent when a consumer requests a return; and - accept signed, bearer-authenticated
POST /returnsrequests idempotently.
The customer also confirms its operational return-routing policy before the
live TESTING gate opens. Physical fulfilment-location IDs are opaque identities;
their numeric values do not imply a return address. A customer may approve one
central destination for several physical locations or a different destination
per location. In either case, every routable physical location must have one
complete, explicitly approved destination in the environment configuration.
SKUU never infers that mapping from the ID, a shop business address or a virtual
network location. Missing or ambiguous routing stays closed for manual review.
Keep event emission and recurring delivery disabled until SKUU explicitly
opens a coordinated TESTING window. Use an existing synthetic Phase-2 order,
never real customer data, for conformance.
Shared request rules
Every body-bearing request uses:
Content-Type: application/json
X-SKUU-Signature: sha256=<lowercase hexadecimal HMAC-SHA256>Calculate the signature over the exact raw UTF-8 JSON bytes sent on the wire:
HMAC-SHA256(shared_secret, exact_raw_request_body_bytes)Verify the signature before parsing JSON or performing a side effect. A
transport retry keeps the identical body bytes, signature, idempotency identity
and embedded timestamps.
IDs are opaque, stable strings. Unless a field says otherwise, canonical
text means a non-empty string with no surrounding whitespace and no ASCII
control characters. Timestamps are RFC 3339 with seconds and an explicit
timezone. Quantities are positive JSON integers from 1 through
2,147,483,647, not strings or deltas. All request objects are closed: do not
add undocumented properties.
1. Send return.created
return.createdSend one signed event for one return request. The event may contain multiple
lines, but all lines belong to the same original consumer order.
POST {skuu_webhook_url}
Content-Type: application/json
X-SKUU-Signature: sha256=<hmac>SKUU supplies the complete environment-specific webhook URL before testing.
Do not derive it or reuse a URL from another environment.
{
"spec_version": "1",
"event": "return.created",
"event_id": "evt_return_01JABC",
"occurred_at": "2026-09-10T09:00:00Z",
"data": {
"return_id": "RET-1001",
"order_id": "ORD-10045",
"created_at": "2026-09-10T08:59:50Z",
"reason": "too_small",
"resolution": "refund",
"customer_note": null,
"lines": [
{
"return_line_id": "RET-LINE-1",
"order_line_id": "LINE-1",
"variant_id": "V-123-38-BLK",
"quantity": 1,
"reason": "too_small"
}
]
}
}Envelope fields
| Field | Type | Rules |
|---|---|---|
spec_version | string | Required; exactly "1" |
event | string | Required; exactly "return.created" |
event_id | string | Required; globally unique logical-event identity, 1–255 canonical characters |
occurred_at | RFC 3339 timestamp | Required; timezone-aware source event time |
data | object | Required; closed return-request object |
Return fields
| Field | Type | Rules |
|---|---|---|
return_id | string | Required; stable customer-native return identity, unique within the source customer, 1–255 canonical characters |
order_id | string | Required; exact original consumer-order identity previously sent in Phase 2, 1–255 canonical path-safe characters; it cannot be . or .. and cannot contain /, \, ?, # or % |
created_at | RFC 3339 timestamp | Required; timezone-aware time at which the return was requested |
reason | string | Required; non-empty canonical request-level reason, maximum 255 characters |
resolution | string | Required; non-empty canonical requested outcome, maximum 64 characters; it does not authorize or execute a refund |
customer_note | string or null | Optional; when present, non-empty canonical text, maximum 5,000 characters |
lines | array | Required; 1–1,000 unique return lines |
Line fields
| Field | Type | Rules |
|---|---|---|
return_line_id | string | Required; unique within this return, 1–255 canonical characters |
order_line_id | string | Required; exact original consumer-order line identity, unique within this return, 1–255 canonical characters |
variant_id | string | Required; exact original customer variant identity for that order line, 1–255 canonical characters |
quantity | integer | Required; positive absolute requested quantity from 1 through 2,147,483,647 |
reason | string | Required; non-empty canonical line-level reason, maximum 255 characters |
Important behavior:
- SKUU validates every line before writing anything. A rejected line cannot
leave a partial return. - The source customer, order, order line and variant identities must agree.
- A valid first delivery is stored atomically as
pending_review. Intake never
approves the return, creates a refund, changes an order, writes financial
records or calls another customer. During later operator review, every line
must resolve through the original Phase-2 order data to exactly one recorded
seller-side physical fulfilment location. Zero or multiple matches keep it
unroutable and prevent approval or outbound creation. - The cumulative quantity across
pending_reviewandapprovedreturn
requests cannot exceed the original ordered quantity. event_idplus the SHA-256 hash of the exact signed request body controls
replay. An exact replay is a duplicate. Reusing an event ID with changed
bytes is a conflict and creates no second return.- Reusing a customer-native
return_idfor another event is also a conflict. - Source timestamps more than five minutes in the future are permanently
rejected without a write.
SKUU webhook response matrix
| HTTP | Meaning | Customer action |
|---|---|---|
200 | The signed delivery was acknowledged. This covers a first valid request, exact replay, disabled receiver, or a permanently invalid/conflicting business request. The body is empty and non-contractual; 200 alone is not proof of a database write. | Stop. Use bilateral conformance evidence to distinguish pending_review, duplicate and rejected outcomes. |
401 | HMAC authentication is missing or invalid, or the customer route is unavailable without revealing its existence. | Do not retry automatically; correct the credential or signing implementation. |
413 | Raw body exceeds 512 KiB. | Do not retry unchanged; reduce the request to the documented contract. |
5xx | A valid event could not complete durable storage. | Retry the identical event ID, body and timestamps with backoff. |
The customer sender retries network failures and SKUU 5xx responses with
backoff and stops on every 200. Permanent signed schema or business errors
are acknowledged to prevent an infinite retry loop.
2. Implement POST /returns
POST /returnsExpose one customer-hosted endpoint that creates an approved return for one
original seller order and one physical fulfilment location.
POST {customer_api_root}/returns
Authorization: Bearer <token>
Content-Type: application/json
X-SKUU-Signature: sha256=<hmac>{
"external_ref": "skuu-return-<opaque-stable-value>",
"order_id": "SELLER-ORDER-5001",
"status": "approved",
"destination": {
"name": "Returns Warehouse",
"address_line1": "Warehouse Street 1",
"address_line2": null,
"postal_code": "1000 AA",
"city": "Amsterdam",
"country_code": "NL"
},
"lines": [
{
"order_line_id": "skuu-line-01JABC",
"variant_id": "SELLER-VARIANT-38-BLK",
"quantity": 1
}
]
}Request fields
| Field | Type | Rules |
|---|---|---|
external_ref | string | Required; opaque SKUU idempotency identity, 1–255 canonical characters |
order_id | string | Required; exact customer-native seller order created through Phase-2 POST /orders, 1–255 canonical characters |
status | string | Required; exactly "approved" |
destination | object | Required; closed physical return destination |
lines | array | Required; 1–1,000 unique seller order lines |
Destination fields are name (maximum 255 characters), address_line1
(maximum 255), optional address_line2 (maximum 255; it may be omitted or
null), postal_code (maximum 32), city (maximum 100) and an uppercase
two-letter country_code. All strings are non-empty canonical text when
present.
Each line contains the seller-side order_line_id originally supplied as the
line external_ref in Phase-2 POST /orders, the seller-native variant_id
and a positive absolute quantity. Both IDs are 1–255 canonical characters;
the quantity is a JSON integer from 1 through 2,147,483,647. These are
seller identities; they are not the buyer-native IDs from the inbound event.
Return HTTP 200 with exactly this body shape:
{
"success": true,
"message": "Successfully created return.",
"external_ref": "skuu-return-<opaque-stable-value>",
"return_id": "RET-5001",
"status": "approved"
}Important behavior:
external_refis the idempotency key and must be echoed exactly.return_idis the stable customer-native identity of the created return and
must contain 1–255 canonical characters.- An identical replay returns the original return and the identical success
receipt. It must not create a second return, label, notification or other
side effect. - Reusing an
external_refwith a different payload returns HTTP409with
error.code=idempotency_conflict. - Unknown
order_idororder_line_idreturns HTTP404without a partial
return. - Only HTTP
200is a successful create or identical replay. HTTP201and
success bodies with missing, changed or extra fields do not satisfy the v1
contract.
Customer-hosted response matrix
Errors use the standard closed envelope:
{
"error": {
"code": "unknown_order",
"message": "The supplied order_id does not exist"
}
}error.code is stable and machine-readable. error.message is diagnostic
text for operators and must not be used as the programmatic decision key.
| HTTP | Stable code or meaning | SKUU action |
|---|---|---|
200 | Exact five-field success receipt | Stop and durably record the receipt. |
400 | Permanent request error | Do not retry unchanged; correct the request. |
401 | unauthorized | Bearer or HMAC authentication is missing or rejected. Do not retry automatically; correct the credential or signature. |
403 | forbidden | Valid credentials do not have access to this operation. Do not retry automatically; correct the access policy. |
404 | unknown_order or unknown_line | Do not retry unchanged; resolve the seller identity. |
409 | idempotency_conflict | Stop and investigate changed-payload reuse of external_ref. |
429 | Rate limited | Retry identical signed bytes with backoff and honour numeric-seconds Retry-After. |
5xx | Temporary server failure | Retry identical signed bytes with the same external_ref and signature. |
SKUU uses a bounded retry policy for network failures, HTTP 429 and HTTP
5xx. Other 4xx responses and invalid success receipts are permanent until
an operator corrects the cause.
Review and routing behavior
One inbound request can span lines fulfilled by different sellers, seller
orders or physical locations. After operator approval, SKUU:
- resolves every line to the original seller order, seller line, variant and
exactly one physical fulfilment location recorded during Phase 2; zero or
multiple location matches are unroutable and remain for manual review; - rejects same-source loops and any missing, inactive, incomplete, virtual or
unapproved destination. In customer terms, a line whose original seller is
the same customer that emitted the return request is not routed back through
SKUU; Phase 3 outbound creation targets a different SKUU Connect seller; - loads the destination only from the authoritative active physical-location
directory—never from a virtualSKUU_Networklocation or a shop YAML or
business-address fallback. The customer owns the mapping decision: one
approved central address may be recorded for several physical locations, or
each location may have its own approved address; - groups lines by seller customer, seller order and physical location;
- assigns one deterministic opaque
external_refto every group; and - sends one
POST /returnsrequest per group in deterministic order.
The live release seam durably freezes the complete validated JSON request for
every group before the first external call. Replanning the same reviewed return
must reproduce the exact same set of groups, references and bodies; missing,
extra or changed groups fail closed instead of overwriting the plan. Accepted
groups retain their exact customer receipt. A retry skips already accepted
groups and sends only prepared groups with their frozen request bodies.
This is an exactly-once-ish business-effect contract, not a claim that an
HTTP network provides exactly-once delivery. Webhook and outbound transports
may deliver more than once. Stable event/reference identities, frozen bytes,
atomic first-write/conflict checks and exact receipt replay ensure that an
identical retry has one logical effect, while changed-payload reuse fails
closed.
There is deliberately no automatic release from the inbound webhook. An
operator must review the complete request and approve or reject it first. An
identical repeat review is safe; a conflicting second review decision fails
closed.
Dry-run is different from a live release: it validates and builds the complete
plan locally but sends no HTTP request and persists no dispatch plan, frozen
body or receipt.
Operator review and release
This section is for SKUU operators. Customers implement the two wire
interfaces above; they do not run these commands.
Review and release are deliberately separate commands:
skuu returns connect-review --return-id <internal-uuid> --decision approved
skuu returns connect-review --return-id <internal-uuid> --decision rejected
skuu returns connect-release --return-id <internal-uuid>connect-review records one explicit terminal decision and never performs an
outbound call. connect-release accepts only an approved request, resolves the
target customer from the existing shop configuration, honours the independent
creation gate and dry-run mode, and emits a machine-readable redacted result.
In live mode it freezes the complete dispatch plan before transport; rerunning
the command skips accepted groups and resumes only prepared groups with their
original bytes and signatures. Missing, duplicate or inconsistent target
configuration fails closed.
Testing and activation
SKUU-side automated Phase-3 verification passes the strict inbound/outbound,
replay, conflict, routing, review, dry-run, frozen-plan and durable-resume
matrix.
The Phase-3 persistence/runtime foundation is installed in shared TESTING and
its access-control and empty-baseline readback has passed. This platform
foundation does not activate a customer:
customer implementation and bilateral conformance have not occurred, and
customer event emission, the SKUU receiver, live outbound writes, recurring
delivery and production all remain closed. Safe runtime defaults stay
returns.receiver_enabled=false, returns.creation_enabled=false and
returns.creation_dry_run=true.
The stable OpenAPI companion remains Phase 1 plus Phase 2. Phase 3 stays out of
that machine-readable contract until bilateral acceptance.
Activation proceeds in separate, explicitly approved steps:
- Complete and mutually sign off Phases 1 and 2.
- Customer implements both Phase-3 interfaces with TESTING credentials while
event emission remains disabled. - Customer confirms which complete return destination applies to every
eligible physical fulfilment location; SKUU records only that approved
mapping and does not infer it from IDs or another address source. - Before the customer window, re-read the installed TESTING schema, service-role
RPC access and customer-specific empty baseline; stop if any preflight fails. - Keep
returns.receiver_enabled=false,returns.creation_enabled=false,
andreturns.creation_dry_run=trueuntil those preflights pass and the
bounded bilateral window is separately approved. - Run signed inbound first-delivery, exact-replay, changed-payload conflict,
identity and cumulative-quantity checks using one synthetic Phase-2 order. - Review the stored request manually and prove approval/rejection idempotency.
- Prove a dry-run release creates no transport or durable dispatch record.
- Open only the bounded live TESTING write gate and prove one grouped
POST /returns, exact customer replay and durable receipt/resume behavior. - Close the window, verify no unexpected business, financial or production
effects, and exchange bilateral Phase-3 sign-off. - Enable recurring event delivery and production only in later, separately
approved cutovers.
Return labels, carrier tracking, warehouse inspection, refund execution,
consumer notifications and cost allocation are outside this Phase-3 preview.
They require a later documented contract revision.
Updated about 7 hours ago
