{"openapi":"3.0.3","info":{"title":"Tangibl creations and orders","version":"1.0.0","description":"Assistants connect to Tangibl through its MCP server at https://gettangibl.com/api/mcp (Streamable HTTP, OAuth 2.0 with dynamic client registration at https://gettangibl.com/oauth/register and PKCE S256). Setup: https://gettangibl.com/connect. Usage guide: https://gettangibl.com/connect/usage. This REST API offers the same operations for custom integrations, with the same OAuth sign-in; a token requested for one endpoint (resource parameter) is not accepted by the other. Tangibl is a print service: it turns conversation images into physical products and shows previews. When a customer mentions Tangibl, they mean this connector, not text to put in the image. Usage guide: /connect/usage. Print-ready artwork is composed for the product shape from the start. Before any upload, check the image against the product ratio. Create and send the flat artwork itself, never a picture of the product: no mug, frame, wall, room, mockup or person wearing it. Tangibl makes the product preview from the artwork. If the image does not match, recreate it natively at the product ratio: regenerate the same scene, subject and style with the correct aspect ratio, or outpaint it with real, coherent scene content. Then show the recomposed image and say in one short sentence that you adapted it to fit the product. Never pad, letterbox or fill to fit: no blurred, smeared, mirrored, stretched or solid-colour bars or borders (canvas wrap edges are added by Tangibl, not by you). Never crop away part of the subject. Be proactive: whenever the customer mentions Tangibl, printing, framing, a canvas, a poster, a wall, a T-shirt, a hoodie, a mug, stickers, a blanket, playing cards or a gift, create new images directly in the shape that product needs (each product generation_hint: wall art uses the chosen size_options artwork requirements; canvas uses the selected size accepted_ratios, e.g. 2:3 or 3:4 for 24x36; stickers a cut-out on a transparent background; blanket landscape; playing cards 5:7) at high resolution, instead of a default square or wide image. If unsure of the product, ask which one before generating. When the customer names a wall-art product (canvas, poster, photo, framed or metal print) before the image exists, your first reply is the size question; generate only after they answer, directly at the ratio for that size. Keep important details (faces, text, signs) away from the outer edges: frames cover a few millimetres, canvas edges wrap around the sides, playing cards are trimmed and blanket edges wrap into the hem. Give every creation a short name the customer would recognize (for example \"Fox in the snow\") when saving it, and add the occasion and a note when the customer mentions them. The occasion is the event or reason (for example \"Mom's birthday\", \"Christmas\", \"housewarming\"); the note is anything else worth remembering (for example \"for the reading nook\", \"use warmer colors next time\"). Customers come back to creations by name: listMyDrafts shows names, and updateDraftDetails renames or adds details when asked. After every save, show the product preview in the conversation without being asked: poll getDraftProof until image_url is set (usually under a minute), then show getDraftProofImage inline. A canvas is uploaded as flat artwork at the selected size ratio with product_id=canvas-print and size; Tangibl adds the wrapped edges. For deletion, ask the customer to identify the creation by name; never infer it from age or recency. requestDraftDeletion shows the exact name, artwork and product preview in a chat widget. Nothing is deleted until the customer reviews the exact name and preview and clicks Confirm deletion in that widget. Direct API deletion is disabled; never confirm for them. Customers are usually not technical: plain language works best, and operation names, IDs and technical sizes are rarely useful to them unless they ask. Ordering: only when listProducts says ordering_available is true for this customer. For wall art, choose the size before uploading and pass size to uploadDraft or uploadCanvasPrintFile. Checkout uses the saved draft size; to change it, create and review a new draft using reviseDraftProduct with size (canvas requires a new upload). For a T-shirt or hoodie, ask the customer's size (sizes in listProducts) and pass it as size to startCheckout; stickers default to 4×4 in unless the customer picks 3×3 or 5.5×5.5. That flag and ordering_notice are specific to the signed-in customer and take precedence over general statements on the Tangibl website (which describe the public launch). Prices in listProducts include standard US shipping: say \"shipping included\", never \"free shipping\". The Stripe checkout page shows shipping as its own line, and promotion codes discount the product, not shipping. Before confirming a larger wall-art order, call listProducts with product_id and size to quote that exact size; the unfiltered catalog only prices the default. Where it ships: the address book (listAddresses) holds labelled addresses such as \"Me\" and \"Mom\", in the US or Colombia. Colombian orders need a saved Colombian address (createAddressLink) before checkout; their shipping costs more and is quoted at checkout (the listProducts prices are for the US), and canvas, metal prints and playing cards don't ship there. When the customer names someone (\"send it to me\", \"to my mom\"), pass that address_id to startCheckout or checkoutCart; if more than one could match, ask. If they name nobody, confirm the default address with them before checkout (\"Ship to Me: 12 Oak St, Brooklyn, NY?\"), or ask which one when there is no default. Never make an address the default unless the customer asks. For someone not in the address book, call createAddressLink, give the customer address_url, then getAddressLink and read the address back. Never collect or type an address in the chat. While the address book is empty, a US customer's own first order needs no address_id: the checkout page asks for the address and saves it as \"Me\". One order ships to one address: items for different people need separate checkouts. When the customer wants to buy, confirm the item, quantity, total and recipient, call startCheckout, then complete payment on checkout_url, a Stripe checkout page with a standard card form (it offers to save the card, and shows saved cards next time), with the customer approving the payment (or give them the link to pay themselves). Never pay without the customer's explicit approval of the total. Describe order progress in Tangibl's own words (made to order by Tangibl, production and shipping times, tracking by email); never name or mention a print partner, supplier or manufacturer. Several creations in one order (cheaper: one shipment, and each extra item adds little shipping): use the cart. addToCart each creation (draft_id, size where needed, quantity), show getCart (items, shipping, total) to the customer, then checkoutCart for one checkout_url covering everything. The cart is saved and emptied once that order is paid; removeCartItem or updateCartItem change it. When the customer asks to put creations together or to add one more, use the cart instead of separate checkouts. startCheckout remains the shortcut for a single creation. A customer with a promo code enters it on the checkout page (Add promotion code); the discounted total shows there before paying. getOrder shows whether payment went through. When ordering_available is false, the creation stays saved for when ordering opens. Returns and reprints: every item is personalized and made to order, so there are no returns or refunds for change of mind. Tangibl reprints only proven misprints (a production error, shown in a photo) reported within 30 days of delivery. Mention this in one short sentence before checkout. To report a misprint, give the customer report_problem_url from getOrder; they add the photos there. Full policy: /returns"},"servers":[{"url":"https://gettangibl.com"}],"security":[{"tangiblOAuth":["drafts"]},{"personalBearer":[]}],"components":{"securitySchemes":{"tangiblOAuth":{"type":"oauth2","description":"Preferred. Dynamic client registration at /oauth/register (no client ID needed); tools that take a client ID can use tangibl (public, no secret). token_endpoint_auth_method none; PKCE S256 required. Metadata: /.well-known/oauth-authorization-server.","flows":{"authorizationCode":{"authorizationUrl":"https://gettangibl.com/oauth/authorize","tokenUrl":"https://gettangibl.com/oauth/token","refreshUrl":"https://gettangibl.com/oauth/token","scopes":{"drafts":"Save creations, show previews, list drafts, send feedback. Cannot order or pay."}}}},"personalBearer":{"type":"http","scheme":"bearer","description":"Fallback: a personal key the customer copies from /account/muse."}}},"paths":{"/api/v1/products":{"get":{"operationId":"listProducts","parameters":[{"name":"product_id","in":"query","schema":{"type":"string","enum":["photo-print","poster","framed-print","canvas-print","metal-print","t-shirt","hoodie","mug","stickers","blanket","playing-cards"]}},{"name":"size","in":"query","schema":{"type":"string","description":"Wall-art size from listProducts sizes, e.g. 18x24. Select before preparing artwork; use its size_options geometry. Omit only to use the product default."},"description":"With product_id, returns the live price for this size before checkout."}],"description":"Call this as soon as the customer mentions Tangibl or a physical product, before generating or preparing an image. Follow assistant_instructions and use each product generation_hint when creating artwork.","responses":{"200":{"description":"Wall art (five wall-art products with sizes up to 24×36; posters start at 18×24) and merch (T-shirt, hoodie, mug, stickers, blanket, playing cards) with prices (US shipping included; apparel priced at size M, larger sizes cost more) and whether ordering is available for this customer. Every product has an instant preview. Wall art (canvas included) takes flat artwork matching the selected size ratio, and Tangibl adds canvas wrap edges; merch accepts any artwork of at least 1000 px and composes it for the product (see each generation_hint and recommended_ratios)","content":{"application/json":{"schema":{"type":"object","properties":{"products":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["photo-print","poster","framed-print","canvas-print","metal-print","t-shirt","hoodie","mug","stickers","blanket","playing-cards"]},"name":{"type":"string"},"size":{"type":"string"},"proof_capability":{"type":"string","enum":["tangibl_preview"]},"category":{"type":"string","enum":["wall_art","merch"]},"sizes":{"type":"array","items":{"type":"string"},"description":"Sizes for startCheckout size"},"size_options":{"type":"array","items":{"type":"object"},"description":"Per-size artwork requirements and canvas full-wrap geometry. Choose before generation and upload."},"default_size":{"type":"string","nullable":true,"description":"Null means the customer must choose (T-shirt, hoodie)"},"recommended_ratios":{"type":"array","items":{"type":"string"},"description":"Merch: artwork shapes that fit without cropping or empty space"},"supplier_photo":{"type":"boolean"},"image_requirements":{"type":"object","description":"Portrait/landscape ratio, recommended pixels and full-image fit policy for uploadDraft"},"full_wrap_artwork":{"type":"object","description":"Canvas only: file size, front area and wrap band for uploadCanvasPrintFile"},"price":{"type":"object","nullable":true,"description":"amount_cents, display, shipping (\"US shipping included\"), shipping_included (the shipping part, e.g. \"$4.49\"), delivery_business_days"}}}},"ordering_available":{"type":"boolean"},"ordering_test_mode":{"type":"boolean"},"ordering_notice":{"type":"string","description":"Customer-specific ordering status; takes precedence over the public website"}}}}}}}}},"/api/v1/uploads":{"post":{"operationId":"uploadDraft","description":"Save artwork for a product: wall art (photo print, poster, framed or metal print) or merch (T-shirt, hoodie, mug, stickers, blanket, playing cards). Its product preview is ready immediately (getDraftProof status preview_ready); show getDraftProofImage in the conversation without being asked. With product_id=canvas-print this behaves exactly like uploadCanvasPrintFile. For wall art pass size and compose to its size_options image_requirements, at 150 PPI or more (minimum_pixels_portrait/landscape; smaller is refused with resolution_too_low, naming the sizes the image fits); merch artwork is composed for the product by Tangibl (stickers: a cut-out on a transparent PNG background). If the image has the wrong shape, recreate it at the right ratio first; never pad it with blurred or solid bars, and never crop the subject.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":100},"description":"New UUID per intended draft, reused on retry."},{"name":"parent_id","in":"query","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"product_id":{"type":"string","enum":["photo-print","poster","framed-print","canvas-print","metal-print","t-shirt","hoodie","mug","stickers","blanket","playing-cards"]},"size":{"type":"string","description":"Wall-art size from listProducts sizes, e.g. 18x24. Select before preparing artwork; use its size_options geometry. Omit only to use the product default."},"name":{"type":"string","maxLength":80,"description":"Short name the customer will recognize, e.g. Fox in the snow"},"occasion":{"type":"string","maxLength":80,"description":"Optional, e.g. Mom's birthday"},"note":{"type":"string","maxLength":500,"description":"Optional note from the customer"}},"required":["file","product_id"]}}}},"responses":{"200":{"description":"Owned customer data or saved draft; never an order","content":{"application/json":{"schema":{"type":"object","properties":{"draft_id":{"type":"string"},"name":{"type":"string","nullable":true},"occasion":{"type":"string","nullable":true},"note":{"type":"string","nullable":true},"product_id":{"type":"string"},"image":{"type":"object"},"review_url":{"type":"string"},"preview_url":{"type":"string"},"proof":{"type":"object","description":"Illustrative mockup metadata or blocked-fit guidance; never supplier-accurate"},"request_id":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Idempotency key reused for different content"},"422":{"description":"Invalid request"},"503":{"description":"Temporarily unavailable"}}}},"/api/v1/canvas/uploads":{"post":{"operationId":"uploadCanvasPrintFile","description":"Save canvas artwork at the selected size as a private draft. Send flat portrait artwork in a shape the size accepts (full_wrap_artwork.accepted_ratios: 8x10 4:5/3:4/1:1, 16x20 4:5/3:4, 18x24 3:4/4:5/2:3, 24x36 2:3/3:4); Tangibl builds the mirror-wrapped print file. Ask the size before generating. Its preview is ready immediately (getDraftProof status preview_ready; show getDraftProofImage right away); an optional extra product photo follows in supplier_mockup. Pass size. Never places an order. Single-frame JPEG or PNG at 150 PPI or more for the size (short side at least 1200 px for 8x10, 2400 for 16x20, 2700 for 18x24, 3600 for 24x36; smaller is refused with resolution_too_low and the sizes it fits), within the 4 MiB direct-upload limit; no wrap band, borders or padding. A ready-made full-wrap file at the full ratio and pixels is also accepted.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":100},"description":"New UUID per intended draft, reused on retry."},{"name":"parent_id","in":"query","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"product_id":{"type":"string","enum":["canvas-print"]},"size":{"type":"string","description":"Wall-art size from listProducts sizes, e.g. 18x24. Select before preparing artwork; use its size_options geometry. Omit only to use the product default."},"name":{"type":"string","maxLength":80,"description":"Short name the customer will recognize, e.g. Fox in the snow"},"occasion":{"type":"string","maxLength":80,"description":"Optional, e.g. Mom's birthday"},"note":{"type":"string","maxLength":500,"description":"Optional note from the customer"}},"required":["file","product_id"]}}}},"responses":{"200":{"description":"Owned customer data or saved draft; never an order","content":{"application/json":{"schema":{"type":"object","properties":{"draft_id":{"type":"string"},"name":{"type":"string","nullable":true},"occasion":{"type":"string","nullable":true},"note":{"type":"string","nullable":true},"product_id":{"type":"string"},"image":{"type":"object"},"review_url":{"type":"string"},"preview_url":{"type":"string"},"proof":{"type":"object","description":"Illustrative mockup metadata or blocked-fit guidance; never supplier-accurate"},"request_id":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Idempotency key reused for different content"},"422":{"description":"Invalid request"},"503":{"description":"Temporarily unavailable"}}}},"/api/v1/drafts":{"get":{"operationId":"listMyDrafts","responses":{"200":{"description":"Up to 50 recent owned drafts","content":{"application/json":{"schema":{"type":"object","properties":{"drafts":{"type":"array","items":{"type":"object"}}}}}}}}},"post":{"operationId":"reviseDraftProduct","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":100},"description":"New UUID per intended draft, reused on retry."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"parent_id":{"type":"string","format":"uuid"},"product_id":{"type":"string","enum":["photo-print","poster","framed-print","canvas-print","metal-print","t-shirt","hoodie","mug","stickers","blanket","playing-cards"]},"size":{"type":"string","description":"Wall-art size from listProducts sizes, e.g. 18x24. Select before preparing artwork; use its size_options geometry. Omit only to use the product default."},"name":{"type":"string","maxLength":80,"description":"Short name the customer will recognize, e.g. Fox in the snow"},"occasion":{"type":"string","maxLength":80,"description":"Optional, e.g. Mom's birthday"},"note":{"type":"string","maxLength":500,"description":"Optional note from the customer"}},"required":["parent_id","product_id"]}}}},"responses":{"200":{"description":"Owned customer data or saved draft; never an order","content":{"application/json":{"schema":{"type":"object","properties":{"draft_id":{"type":"string"},"name":{"type":"string","nullable":true},"occasion":{"type":"string","nullable":true},"note":{"type":"string","nullable":true},"product_id":{"type":"string"},"image":{"type":"object"},"review_url":{"type":"string"},"preview_url":{"type":"string"},"proof":{"type":"object","description":"Illustrative mockup metadata or blocked-fit guidance; never supplier-accurate"},"request_id":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Idempotency key reused for different content"},"422":{"description":"Invalid request"},"503":{"description":"Temporarily unavailable"}}}},"/api/v1/drafts/{id}":{"get":{"operationId":"getDraft","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Owned customer data or saved draft; never an order","content":{"application/json":{"schema":{"type":"object","properties":{"draft_id":{"type":"string"},"name":{"type":"string","nullable":true},"occasion":{"type":"string","nullable":true},"note":{"type":"string","nullable":true},"product_id":{"type":"string"},"image":{"type":"object"},"review_url":{"type":"string"},"preview_url":{"type":"string"},"proof":{"type":"object","description":"Illustrative mockup metadata or blocked-fit guidance; never supplier-accurate"},"request_id":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Idempotency key reused for different content"},"422":{"description":"Invalid request"},"503":{"description":"Temporarily unavailable"}}},"delete":{"operationId":"deleteDraft","description":"Direct API deletion is disabled. Returns confirmation_required; the customer must confirm deletion in the Tangibl chat widget.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"draft_id":{"type":"string"},"versions_detached":{"type":"integer"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Direct deletion disabled; confirmation_required"}}},"patch":{"operationId":"updateDraftDetails","description":"Rename a creation or change its occasion or note, e.g. when the customer says who it is for. Send only the fields to change; an empty string clears occasion or note. Artwork and product never change here.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":80,"description":"Short name the customer will recognize, e.g. Fox in the snow"},"occasion":{"type":"string","maxLength":80,"description":"Optional, e.g. Mom's birthday"},"note":{"type":"string","maxLength":500,"description":"Optional note from the customer"}}}}}},"responses":{"200":{"description":"Owned customer data or saved draft; never an order","content":{"application/json":{"schema":{"type":"object","properties":{"draft_id":{"type":"string"},"name":{"type":"string","nullable":true},"occasion":{"type":"string","nullable":true},"note":{"type":"string","nullable":true},"product_id":{"type":"string"},"image":{"type":"object"},"review_url":{"type":"string"},"preview_url":{"type":"string"},"proof":{"type":"object","description":"Illustrative mockup metadata or blocked-fit guidance; never supplier-accurate"},"request_id":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Idempotency key reused for different content"},"422":{"description":"Invalid request"},"503":{"description":"Temporarily unavailable"}}}},"/api/v1/drafts/{id}/preview":{"get":{"operationId":"getDraftPreview","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Artwork preview to show inline; not a framed proof","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"}}}},"/api/v1/drafts/{id}/supplier-mockup":{"post":{"operationId":"requestSupplierMockup","description":"Optional: start or retry the extra product photo for a full-wrap canvas or poster draft. The product preview does not depend on it (getDraftProof is preview_ready right away). Idempotent per draft; the photo appears in getDraftProof.supplier_mockup when ready. Never creates an order, approval or charge.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product preview state; supplier_mockup shows the extra product photo status","content":{"application/json":{"schema":{"type":"object","properties":{"proof_id":{"type":"string"},"status":{"type":"string","enum":["preview_ready","blocked"]},"kind":{"type":"string"},"image_url":{"type":"string","nullable":true},"readiness":{"type":"object"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Not a full-wrap canvas or poster draft, or mockup retry limit reached"},"429":{"description":"Too many mockups this hour"},"503":{"description":"Temporarily unavailable"}}}},"/api/v1/drafts/{id}/proof":{"get":{"operationId":"getDraftProof","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product preview state: preview_ready (image_url set; show getDraftProofImage right away) or blocked (artwork does not fit; see readiness.guidance). Canvas and poster may include supplier_mockup, an optional extra product photo. Colors on screen can differ slightly from the print","content":{"application/json":{"schema":{"type":"object","properties":{"proof_id":{"type":"string"},"status":{"type":"string"},"kind":{"type":"string"},"image_url":{"type":"string","nullable":true},"readiness":{"type":"object"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"}}}},"/api/v1/drafts/{id}/checkout":{"post":{"operationId":"startCheckout","description":"Start checkout for a saved creation when listProducts says ordering_available is true. Confirm item, size, quantity, total and recipient with the customer first. Pass address_id for where it ships: match who the customer names (\"me\", \"my mom\") in listAddresses; if they name nobody, confirm the default address with them first; for someone new, createAddressLink. T-shirts and hoodies need size (ask the customer); wall art uses the saved draft size and rejects a different checkout size. Prepare and review a new draft to change it. Other products use their default. Returns the total (US shipping included) and checkout_url, a Stripe checkout page with a standard card form, valid about 30 minutes. Complete payment there only after the customer approves the total, or give the customer the link. Idempotency-Key: new UUID per order, reused only to retry.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":100},"description":"New UUID per intended draft, reused on retry."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"quantity":{"type":"integer","minimum":1,"maximum":5,"default":1},"size":{"type":"string","description":"One of the product sizes from listProducts, e.g. M for a T-shirt or 5.5x5.5 for stickers. Required for T-shirt and hoodie."},"address_id":{"type":"string","format":"uuid","description":"Where it ships: address_id from listAddresses or getAddressLink. Required once the customer has saved addresses (otherwise 409 address_required lists them); omit only while the address book is empty, and the Stripe page then asks for the address and saves it as \"Me\"."}}}}}},"responses":{"200":{"description":"Order awaiting payment with checkout_url","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"status":{"type":"string"},"total":{"type":"object"},"ship_to":{"type":"object","nullable":true,"description":"address_id, name and summary of where it ships; null when the checkout page collects the address"},"checkout_url":{"type":"string","nullable":true},"checkout_expires_at":{"type":"string","nullable":true},"test_mode":{"type":"boolean"},"message":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"address_required (the message lists the saved addresses), ordering not open for this customer, artwork does not fit, or Idempotency-Key reused for a different order"},"422":{"description":"Invalid request"},"503":{"description":"Temporarily unavailable"}}}},"/api/v1/cart":{"get":{"operationId":"getCart","description":"The customer's saved cart: creations to order together. Each item has cart_item_id, name, product, size, quantity and price; shipping is one line for the whole shipment; total is what checkoutCart will charge (US shipping included). Items that can no longer be ordered show a problem. ready_to_checkout tells whether checkoutCart can run.","responses":{"200":{"description":"The cart","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}},"item_count":{"type":"integer"},"products":{"type":"object","nullable":true},"shipping":{"type":"object","nullable":true},"total":{"type":"object","nullable":true},"delivery_business_days":{"type":"array","nullable":true,"items":{"type":"integer"}},"ready_to_checkout":{"type":"boolean"}}}}}}}}},"/api/v1/cart/items":{"post":{"operationId":"addToCart","description":"Add a saved creation to the cart (several creations ship together for less). Adding the same creation and size again sets its quantity. T-shirts and hoodies need size (ask the customer); wall art uses its saved draft size. Returns the updated cart.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["draft_id"],"properties":{"draft_id":{"type":"string","format":"uuid"},"size":{"type":"string"},"quantity":{"type":"integer","minimum":1,"maximum":5,"default":1}}}}}},"responses":{"200":{"description":"The cart, plus added_cart_item_id","content":{"application/json":{"schema":{"type":"object","properties":{"added_cart_item_id":{"type":"string"},"items":{"type":"array","items":{"type":"object"}},"total":{"type":"object","nullable":true}}}}}}}}},"/api/v1/cart/items/{cart_item_id}":{"patch":{"operationId":"updateCartItem","description":"Change the quantity of one cart line. Returns the updated cart.","parameters":[{"name":"cart_item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["quantity"],"properties":{"quantity":{"type":"integer","minimum":1,"maximum":5}}}}}},"responses":{"200":{"description":"The cart","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}}}}}}}}},"delete":{"operationId":"removeCartItem","description":"Remove one line from the cart. Returns the updated cart.","parameters":[{"name":"cart_item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The cart","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}}}}}}}}}},"/api/v1/cart/checkout":{"post":{"operationId":"checkoutCart","description":"Check out the whole cart as one order: one Stripe checkout_url (one line per creation plus one shipping line), one shipment to one address. Confirm the items, total and recipient with the customer first. Returns the order like getOrder; the cart is emptied once it is paid, and kept if the checkout expires.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":100},"description":"New UUID per intended draft, reused on retry."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"address_id":{"type":"string","format":"uuid","description":"Where it ships: address_id from listAddresses or getAddressLink. Required once the customer has saved addresses (otherwise 409 address_required lists them); omit only while the address book is empty, and the Stripe page then asks for the address and saves it as \"Me\"."}}}}}},"responses":{"200":{"description":"The order, awaiting payment","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"items":{"type":"array","items":{"type":"object"}},"total":{"type":"object"},"checkout_url":{"type":"string","nullable":true},"message":{"type":"string"}}}}}}}}},"/api/v1/addresses":{"get":{"operationId":"listAddresses","description":"The customer's address book: labelled US and Colombian shipping addresses (\"Me\", \"Mom\") and which is the default. Turn \"send it to me\" or \"to my mom\" into an address_id for startCheckout or checkoutCart; ask if more than one could match.","responses":{"200":{"description":"Saved addresses, default first","content":{"application/json":{"schema":{"type":"object","properties":{"addresses":{"type":"array","items":{"type":"object","properties":{"address_id":{"type":"string"},"label":{"type":"string"},"is_default":{"type":"boolean"},"summary":{"type":"string","description":"One line to read back to the customer"},"name":{"type":"string"},"line1":{"type":"string"},"line2":{"type":"string","nullable":true},"city":{"type":"string"},"state":{"type":"string"},"postal_code":{"type":"string"},"country":{"type":"string"}}}},"message":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"}}}},"/api/v1/addresses/links":{"post":{"operationId":"createAddressLink","description":"Create a single-use Tangibl page (30 minutes) where the customer enters a US or Colombian address with a checked address form, saved under label. For someone not in the address book, or to correct a saved address (the same label replaces it). Give the customer address_url, then call getAddressLink. Never collect or type an address in the chat.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":40,"description":"Short label the customer would say, e.g. Me, Mom, Mom & Dad"}},"required":["label"]}}}},"responses":{"200":{"description":"The page","content":{"application/json":{"schema":{"type":"object","properties":{"address_link_id":{"type":"string"},"address_url":{"type":"string"},"label":{"type":"string"},"expires_at":{"type":"string"},"replaces_address_id":{"type":"string","nullable":true},"message":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"422":{"description":"Invalid request"},"429":{"description":"Too many address pages this hour"}}}},"/api/v1/addresses/links/{address_link_id}":{"get":{"operationId":"getAddressLink","parameters":[{"name":"address_link_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"waiting, saved (with address) or expired","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["waiting","saved","expired","deleted"]},"address":{"type":"object","properties":{"address_id":{"type":"string"},"label":{"type":"string"},"is_default":{"type":"boolean"},"summary":{"type":"string","description":"One line to read back to the customer"},"name":{"type":"string"},"line1":{"type":"string"},"line2":{"type":"string","nullable":true},"city":{"type":"string"},"state":{"type":"string"},"postal_code":{"type":"string"},"country":{"type":"string"}},"nullable":true},"message":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"}}}},"/api/v1/addresses/{address_id}":{"patch":{"operationId":"updateAddress","description":"Rename a saved address or make it the default. The address itself changes only through createAddressLink.","parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":40,"description":"Short label the customer would say, e.g. Me, Mom, Mom & Dad"},"is_default":{"type":"boolean","description":"true makes it the default"}}}}}},"responses":{"200":{"description":"The address","content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"object","properties":{"address_id":{"type":"string"},"label":{"type":"string"},"is_default":{"type":"boolean"},"summary":{"type":"string","description":"One line to read back to the customer"},"name":{"type":"string"},"line1":{"type":"string"},"line2":{"type":"string","nullable":true},"city":{"type":"string"},"state":{"type":"string"},"postal_code":{"type":"string"},"country":{"type":"string"}}}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Another address has that label"}}},"delete":{"operationId":"deleteAddress","description":"Remove an address from the address book. Only when the customer clearly asks, after confirming which one by label. Past orders keep their shipping address.","parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"}}}},"/api/v1/orders":{"get":{"operationId":"listMyOrders","description":"Recent orders, each shaped like getOrder (including review_url and report_problem_url).","responses":{"200":{"description":"Up to 50 recent orders","content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Invalid, expired or revoked connection"}}}},"/api/v1/orders/{id}":{"get":{"operationId":"getOrder","description":"Order status: awaiting_payment (with checkout_url), paid, expired, canceled, needs_review or refunded. review_url is the customer's order page (status, tracking, reprint policy). If a paid order arrives misprinted or damaged, give the customer report_problem_url: they describe the problem and add 1–3 photos there themselves, within 30 days of delivery. Assistants cannot submit reports or photos.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Owned order","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"status":{"type":"string"},"total":{"type":"object"},"checkout_url":{"type":"string","nullable":true},"fulfillment":{"type":"object","nullable":true,"description":"status and tracking (carrier, tracking_number, tracking_url, shipped_at)"},"review_url":{"type":"string","description":"Order page on the Tangibl website"},"report_problem_url":{"type":"string","nullable":true,"description":"Paid orders only: where the customer reports a misprint with photos"},"message":{"type":"string"}}}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"}}}},"/api/feedback":{"post":{"operationId":"sendFeedback","security":[{},{"personalBearer":[]}],"description":"Send feedback to the Tangibl team on the customer's behalf (ideas, problems, requests). Ask the customer before sending and summarize what you will send. Never include keys, payment details or other people's personal data. The Bearer key is optional and links the feedback to the customer account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":5,"maxLength":4000},"topic":{"type":"string","enum":["idea","problem","product","integration","account","other"]},"agent_name":{"type":"string","maxLength":60,"description":"e.g. Muse"},"context":{"type":"string","maxLength":500,"description":"What the customer was doing"},"name":{"type":"string","maxLength":100},"email":{"type":"string","maxLength":254,"description":"Only if the customer wants a reply"}},"required":["message"]}}}},"responses":{"200":{"description":"Feedback received","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean"},"reference":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Invalid request"},"429":{"description":"Too many messages; try again later"}}}},"/api/v1/drafts/{id}/proof/image":{"get":{"operationId":"getDraftProofImage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Product preview drawn from the exact print file (or, with ?source=supplier, the saved extra product photo); use the Bearer credential to display inline","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Invalid, expired or revoked connection"},"404":{"description":"Not found or not owned"},"409":{"description":"Artwork does not fit the product, or the extra product photo is not ready (source=supplier)"}}}}}}