App-owned line artifacts

Attach private versioned files, authorize previews and consume quantity-aware lifecycle events.

Use this contract for artwork, engraving proofs and other files needed for a particular line. It is available to apps through their declared capabilities; it does not depend on an app name or ID. The app stores the files and controls its retention policy. Tringify supplies authorized references, checkout linkage and lifecycle events. An artifact property stores an opaque identity, not a public download URL.

Declare and release#

  1. In Developer Portal, request the scopes required by the line owner types and order access you use. Declare a string cart_line field with app_access=private and buyer_access=read.

  2. Set line_artifact with thumbnail=true and an explicit public HTTPS runtime_origin. The origin has no path, query, fragment or credentials. Keep the runtime independent from the merchant Admin UI URL when needed.

  3. For wishlist support, add a matching wishlist_line declaration. For explicit order metafield transfer, add the matching string order_item key and enable transfer_to_order_line.

  4. Publish the release and update the store installation. Draft settings do not change an installed app. Check the installation's effective release, granted scopes and readiness errors in Developer Portal before testing.

cart-line-artifact-declaration.json json
{
  "key":"design_ref","name":"Artwork","owner_type":"cart_line","type":"string",
  "app_access":"private","merchant_access":"read","buyer_access":"read",
  "line_artifact":{
    "runtime_origin":"https://files.example.com","thumbnail":true,
    "default_lease_seconds":2592000,"max_lease_seconds":7776000,
    "transfer_to_order_line":true
  }
}

This example also requires a string order_item declaration named design_ref. Do not combine line_artifact with the separate presentation field. Lease values are integer seconds: minimum 3,600, platform maximum 7,776,000 (90 days). The default is 2,592,000 (30 days); the declared maximum must be at least the default. An attachment's requested lease must stay within these bounds.

An artifact property stores an opaque identity that only your app can act on. With merchant_access=read merchants see the reference, read-only, in the item's Metafields list; with hidden they never see it. hidden is the safer default: staff cannot mistake an internal ID for editable order data, and the artwork itself is already presented to them through the authorized preview. Never declare read_write for a reference your app alone can honour.

Attach from a storefront surface#

A surface authorized for cart.add_lines sends lines with product_id, variant_id when applicable, quantity, ordinary properties and an artifacts array. Each artifact supplies property_key, artifact_id, positive version, thumbnail_token and optional lease_seconds. The artifact ID is at most 128 characters and the thumbnail token at most 512. Finalize an immutable version before attaching it. A later edit creates a new version; it must not silently change an already ordered file.

surface-line.json json
{"product_id":123,"quantity":1,"artifacts":[{"property_key":"app:example.design_ref","artifact_id":"design-123","version":1,"thumbnail_token":"app-issued-opaque-capability","lease_seconds":2592000}]}

Preview authorization#

The thumbnail token locates an artifact; it is not sufficient authorization. Platform requests carry X-Tringify-Artifact-Access. Verify the supplied token by POSTing {"token":"..."} to https://api-store.tringify.com/api/2025-01/app-bridge/line-artifact-access/exchange. The successful data contains app_id, store_id, runtime_origin, access, capability_hashes and expires_at. Require your app ID, the exact store and runtime origin, an unexpired grant and the SHA-256 hash of every requested capability. Grants last one minute; verification does not issue an API session or renew them. Never put grants or private capabilities in public image URLs, logs or analytics.

Runtime operation

Purpose

POST /runtime/line-artifacts/thumbnails with {capabilities:[...]}

Authorized preview batch used for line presentation; require preview access

GET /runtime/line-artifacts/thumbnail/{capability}

Authorized individual preview; require preview access

The preview batch response is {proofs:[{capability,content_type,data}]}, with one entry per requested capability and base64-encoded image bytes in data. Batches contain at most 20 capabilities. Acceptable preview types are image/jpeg, image/png and image/webp; each decoded preview is at most 500 KiB. Send an X-Artifact-Checksum header with every individual preview: the lowercase hex SHA-256 of the exact bytes. Tringify checks it for every file it relays and refuses a file whose bytes don't match, recording the mismatch against your app. Use bounded request timeouts, validate response sizes and content types, and fail closed if access verification is unavailable. Return an unavailable-file preview after a permitted deletion instead of exposing another version. Cart, checkout, order presentation, customer order/tracking views and order email previews use the artifact reference; the original product image remains separate. Editing a product image does not change the ordered artwork.

Production files#

Tringify never fetches, renders or inspects your production files. Your app owns them, and it has no say in cart, checkout or payment: checkout never waits on your artifacts. Validate what the shopper supplies before you attach it to a line, so a file you accepted is one you can produce.

Emails Tringify sends to the shopper, such as the order confirmation, show the product image and never your files, so your runtime can never delay them. If the shopper should see their design, send it in your own email.

After payment, app.order_line_artifact_linked names the order line, the artifact and its version. Produce the production file then if you haven't already, and serve it to fulfillment partners from your own runtime; fulfillment artifact contexts name the same artifact and version. Delivery of every lifecycle event retries until your app accepts it.

Lifecycle and partial fulfillment#

Consume the mandatory app lifecycle events for app.cart_references_changed, app.wishlist_references_changed, app.order_line_artifact_linked, app.order_line_artifact_hold_changed and app.order_line_artifact_fulfillment_changed. Verify lifecycle delivery signatures and installation identity. These are separate from optional store data webhook subscriptions. See the lifecycle event reference for the full envelope and fields.

Fulfillment field

How to use it

order_line_artifact_id, artifact_id, artifact_version

Identify the exact linked artifact; do not use only the product ID

sequence

Accept only a newer snapshot per order-line artifact; ignore exact duplicates and older sequences

ordered_quantity, shipped_quantity, delivered_quantity

Use totals for this item, including split fulfillments. Delivery of one unit out of three is partial.

fully_shipped_at, fully_delivered_at

Completion timestamps are present only when the whole item quantity reaches that event

cancelled_at, order_created_at

Support explicit cancelled and never-completed retention policies

A reversal can reduce shipped or delivered quantities and clear completion timestamps. Replace the prior state with the newer snapshot and recalculate the deadline. Do not interpret the first delivery event as full delivery, nor a duplicate delivery as a new retention start. Receive snapshots safely even when they arrive before the order-link event. The Developer Portal provides downloadable synthetic fixtures for partial/full fulfillment, duplicates, stale sequence and reversal tests; downloading them sends no business events.

Retention is part of your merchant experience#

Expose retention controls inside your app's merchant Admin UI, not only in developer configuration. Explain the chosen event, number of days, cancellation policy, never-completed policy and uninstall consequences. Show quantities, the current deadline, what is protecting a file, holds and the actual deletion result. Make applying changed defaults to existing files explicit. Provide a hold or extension when a merchant needs to keep files longer.

Before deleting a file family, check every live cart/wishlist lease, checkout reservation, linked order, hold and extension referring to that version or shared source. A single expired reference is not proof that the file is unused. Claim deletion atomically, reject late holds honestly once irreversible deletion has started, delete every generated output and source, and retry failed deletions durably. Old or duplicate lifecycle messages must never recreate a deleted file. Keep minimal deletion receipts for replay safety and state your metadata retention separately from file retention. There is no public file-deleted acknowledgement endpoint in this contract; successful lifecycle delivery is not evidence that storage deletion has finished.

The app chooses and documents its own retention periods; Tringify's line lease is not an order file retention setting. For the merchant controls and default periods in Tringify Custom Products, see Customization files.