Skip to main content

Overview

Payment and delivery are separate in Shoppex. An order can be paid with status: "COMPLETED" while one of its line items is still waiting for delivery. Use asynchronous fulfillment when your system needs more than 15 seconds to generate content. Use manual fulfillment when a merchant needs to prepare an account, link, code, or file after payment.
Fulfillment is tracked per line item. The invoice payment status does not change when a line item moves between delivery states.

Delivery States

A line item enters AWAITING_FULFILLMENT in either of these cases:
  • its dynamic delivery callback returns an explicit {"status":"pending"} acknowledgement
  • it belongs to a DYNAMIC product that has no dynamic_webhook URL configured
The second case is the manual fulfillment lane. After payment, the merchant can deliver the line item from the dashboard or through the Developer API.

Read Fulfillment State

Order read responses expose these fields on every item. The example below shows the relevant response fields:
id is the line item ID used as {item_id} in the fulfillment endpoints. The order path accepts the same order identifier used by the existing order endpoints.

Fulfill a Line Item

The order must be paid with status: "COMPLETED", and the line item must not already be delivered. Provide at least one of message, codes, links, or files.
cURL
A successful response returns the delivered line item content:
Each files[].attachment_id must refer to an existing attachment owned by the same shop. Upload attachments in the dashboard before calling this endpoint. If any attachment is missing or belongs to another shop, the entire request fails and no partial delivery is stored.

Customer Email

notify_customer controls the buyer’s “product ready” email:
  • omit it or set it to true to request the customer email after the content is stored
  • set it to false to store the content without sending that email
The shop’s normal customer-email settings and notification preferences still apply. Shoppex also emits order:item.delivered after a successful fulfillment.

Error Responses

Both endpoints reject invalid requests with the standard error envelope. The message distinguishes the cause:

Idempotency

Both fulfillment endpoints support the standard Idempotency-Key header. Reuse the same key when retrying the same request after a network interruption. Shoppex scopes the key to the authenticated API key and route and replays the stored response during the 24-hour idempotency window. For example, every retry of the delivery above should keep Idempotency-Key: fulfill-order_123-018f6f2e-7c3a-7b21-9d4e-5a1b2c3d4e5f-v1.
Rejected responses (4xx) are replayed too: after correcting a rejected request body — for example a wrong attachment_id — send the corrected request with a new Idempotency-Key. Reusing the old key returns either the stored error or a key-conflict error.
Idempotency does not allow a line item to be delivered twice. Once delivered_at is set, another fulfillment attempt is rejected even if it uses a different key.

Retry Failed Dynamic Delivery

This endpoint re-queues a failed dynamic delivery and moves the line item from FAILED to PENDING. It does not take a request body.
cURL
Retrying can cause a double delivery. A timeout or network error is ambiguous: the vendor may have provisioned the product before Shoppex received the failure. Check the vendor system or ensure it deduplicates by X-Shoppex-Idempotency-Key before retrying.
Only a FAILED dynamic line item with a failed delivery event can be retried. If no retryable event exists, fulfill the line item manually instead.

Fulfillment Webhook Events

These are normal merchant webhook events. Subscribe to them in Settings → Webhooks or through the Developer API. They use the normal event-webhook signature, not the product’s dynamic delivery signing secret.

order:item.delivered

Emitted after late content is stored through manual or API fulfillment.

order:item.delivery_failed

Emitted when the single dynamic delivery attempt ends in a terminal failure. Shoppex also marks the line item FAILED and notifies the merchant.
These events report fulfillment state. They do not change or replace payment events such as order:paid.

Next Steps

Dynamic Product Delivery

Implement the synchronous and asynchronous callback contract.

Webhook Events

Verify normal merchant webhook signatures and review event payloads.