Skip to main content
A platform integration embeds Fourthwall merch directly into a product a creator already uses — a link-in-bio page, a creator dashboard, a community tool. The creator never leaves your UI: they browse blank products, drop in artwork, see a live preview, and publish, while your backend provisions a Fourthwall shop and creates real products on their behalf. The worked example for this guide is Linkstand, a product-first “links admin” where every row on the page is a real Fourthwall product created through one guided wizard.
The Channel API requires special access — it is invite only and currently in beta. Your channel must be granted access by Fourthwall, which provisions a dedicated channel.* client for it; reach out to request access. See Authentication and Requesting an access token.

The defining idea: the shop appears on publish

Browsing templates, uploading artwork, and rendering a preview are all shop-less — they go straight through the Channel API on the credential alone. Only on publish does a shop come into play: your backend provisions one (once) and creates the live product against it.
Preview is shop-less; create is shop-bound.
Wizard stepWhat happensAPI callShop?
1 · Pick a productBrowse blank product templatesGET /open-api/v1.0/product-templates/page/{page}No
2 · Add artworkPresigned upload, then register the imagePOST /channel-api/v1.0/upload-urlPOST /channel-api/v1.0/media/imagesNo
3 · PreviewRender preview images synchronouslyPOST /channel-api/v1.0/previewsNo
4 · Details & price → PublishProvision a shop on first publish, then create the productGET /channel-api/v1.0/shops → (first time) POST /channel-api/v1.0/shopsPOST /open-api/v1.0/productsCreates / needs it

Two credential faces, one channel

The same channel credential authenticates two API surfaces:
  • channel-api (/channel-api/v1.0/…) — authorized by the channel bearer alone. Everything shop-less: template browsing, upload, preview, shop lookup, and shop provisioning.
  • open-api (/open-api/v1.0/…) — the product-templates list is shop-less, but product create / list / state / delete are shop-bound: the same bearer plus an X-ShopId header selects the shop you provisioned.

Architecture: a thin backend-for-frontend

Keep the credential on your server. Each /api/* route is a small proxy that attaches the channel credential and forwards to one (or, for publish, a few) Fourthwall endpoints. The browser only ever talks to your own routes.
Creator → your app (browser) → /api/* (server, holds credential) → Fourthwall
Linkstand maps its routes one-to-one onto Fourthwall:
Your routeForwards toShop?
GET /api/templatesGET /open-api/v1.0/product-templates/page/1No
GET /api/channelGET /channel-api/v1.0/channel/currentNo
POST /api/upload-urlPOST /channel-api/v1.0/upload-urlNo
POST /api/mediaPOST /channel-api/v1.0/media/imagesNo
POST /api/previewsPOST /channel-api/v1.0/previewsNo
POST /api/publishshop lookup → create (first only) → POST /open-api/v1.0/productsNeeds one
GET /api/linksGET /channel-api/v1.0/shopsGET /open-api/v1.0/productsNeeds one
PUT /api/links/{id}/visibilityPUT /open-api/v1.0/products/{id}/stateNeeds one
DELETE /api/links/{id}DELETE /open-api/v1.0/products/{id}Needs one

The flow, step by step

1

Connect the channel

Install your channel app and exchange the OAuth code for the channel credential, holding it server-side. Confirm the connection by reading the current channel:
cURL
curl "https://api.fourthwall.com/channel-api/v1.0/channel/current" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
2

Pick a blank product

List blank product templates and let the creator choose one. This is shop-less:
cURL
curl "https://api.fourthwall.com/open-api/v1.0/product-templates/page/1" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
3

Upload and register the artwork

Request a presigned upload URL, PUT the bytes, then register the image to get an imageId. Both calls are on the channel face — no shop yet:
cURL
# 1. presigned URL
curl -X POST "https://api.fourthwall.com/channel-api/v1.0/upload-url" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "fileName": "art.png", "contentType": "image/png" }'

# 2. PUT the bytes to the returned uploadUrl (echo the signed headers)

# 3. register → imageId
curl -X POST "https://api.fourthwall.com/channel-api/v1.0/media/images" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "fileUrl": "<fileUrl from step 1>" }'
4

Render a live preview

Render preview mockups synchronously from the chosen template + imageId. Still shop-less:
cURL
curl -X POST "https://api.fourthwall.com/channel-api/v1.0/previews" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "productId": "<templateId>", "imageId": "<imageId>" }'
5

Publish — the shop boundary

Publish is the only step that needs a shop, and it owns the whole shop lifecycle so your client makes a single call:
  1. GET /channel-api/v1.0/shops — does the channel have a shop yet?
  2. POST /channel-api/v1.0/shopsonly on first publish (idempotent: a second publish reuses the same shop, never a duplicate).
  3. POST /open-api/v1.0/products with the X-ShopId header — create the live product from the same productId + imageId the preview was rendered from.
cURL
curl -X POST "https://api.fourthwall.com/open-api/v1.0/products" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "X-ShopId: $SHOP_ID" \
  -H "Content-Type: application/json" \
  -d '{ "type": "design", "name": "My link", "...": "..." }'
Thread the previewed productId + imageId through your wizard state and reuse them at publish — don’t re-derive the design. The previewed design and the published product are then guaranteed to be the same.

Managing published products

Once a shop exists, manage the catalog on the open-api face with X-ShopId:
  • Show / hidePUT /open-api/v1.0/products/{id}/state (PUBLIC / HIDDEN)
  • ArchiveDELETE /open-api/v1.0/products/{id}
  • ListGET /open-api/v1.0/products

Full example

Read Linkstand end to end — a Next.js app-router project where the BFF in lib/fourthwall.ts is the only module that holds the credential and talks to Fourthwall.