HypeCard Test Harness
● checking…

Share Lifecycle Walkthrough

Run each step in order to create a template, publish a share, and test the public OG page.

1
Create Template
pending
2
Add Template Version
pending
3
Create Share
pending
4
View OG Page (Crawler)
pending
5
Follow Redirect (Human)
pending

Templates

POST /v1/templates
POST /v1/templates/:templateId/versions
GET /v1/templates

Shares

POST /v1/shares
GET /v1/shares/:shareId
POST /v1/shares/:shareId/render Force re-render
GET (public) /s/:shareId OG meta page
GET (public) /m/:shareId/:kind Media asset
DELETE /v1/shares/:shareId

Assets

POST /v1/assets multipart/form-data
GET /v1/assets

Settings

GET /v1/settings/effective

Returns the merged settings for the given scope. Uses the org/space/project IDs from the auth headers above, or you can override them here.

DDC - Data-Driven Content: Lineup Card

Render live team lineup cards as embeddable image URLs. No client payload needed - drop the URL in an img tag and the server fetches live data from Opta and renders the card on first hit, then caches it.

View lineup card

PUBLIC GET /ddc/{orgSlug}/lineup/{fixtureId}.jpg

Fixture index

PUBLIC GET /ddc/{orgSlug}/lineup

Lists all upcoming and recent fixtures for the org. Click any fixture to open its lineup card.

External Data Source (POST - Studio integration)

POST POST /ddc/lineup/source

Studio integration endpoint. The platform POSTs to this fixed URL with project context in the body. DDC reads project.custom_fields.hypecard_orgSlug to identify the org. Configure the Studio element spec with source: { url: ".../ddc/lineup/source", method: "post" } and add hypecard_orgSlug as a project custom field.

External Data Source (GET - direct access)

PUBLIC GET /ddc/{orgSlug}/lineup/source

Same response as POST but reads orgSlug from the URL path. For direct access, curl testing, and development.

Player name mapping

PUBLIC GET /ddc/{orgSlug}/players/names

Returns the current short-name mappings plus the raw Opta matchName strings from the most recent confirmed lineup. Use the Opta names as keys when setting overrides.

Update player short names (authenticated)

PATCH PATCH /ddc/{orgSlug}/config

Merge short-name overrides into the org config. Changes are applied immediately and written to orgs.json so they survive restart.

Upload player headshot (authenticated)

POST POST /ddc/{orgSlug}/players/{optaPlayerId}/image

Upload a JPEG or PNG headshot for a player. The server resizes to 176x176 px and stores under public/static/ddc/players/{orgSlug}/{optaPlayerId}.jpg. Use the player ID from the Opta matchName lookup above.

Studio Extension Preview

Preview the embedded Studio extension tab UI exactly as it would appear when loaded inside a Studio sidebar iframe. Select an org to load the prototype. The URL is /studio/tabs/:orgSlug.

H
Monterosa Studio Preview mode
Select an org above to load the extension UI
How this works: Studio calls GET /lvis/:instanceId/projects/:projectId/tabs which returns this URL. Studio embeds it as an iframe in the project sidebar. The tab page fetches live data from the DDC and HypeCard APIs directly from the browser.

CURL Reference

Copy-paste commands. Replace localhost:3001 with your API host. Set ORG and TOKEN before running.

export API="http://localhost:3001" export ORG="org-001" export TOKEN="dev-token"

Health

curl -s $API/health | jq

Settings

curl -s "$API/v1/settings/effective?orgId=$ORG" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" | jq

Create template

curl -s -X POST "$API/v1/templates" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Score Card"}' | jq

Add template version

curl -s -X POST "$API/v1/templates/$TEMPLATE_ID/versions" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "html": "<h1>{{name}} scored {{score}}</h1>", "previewType": "image", "variables": [ {"name":"name","required":true}, {"name":"score","required":false,"defaultValue":"0"} ] }' | jq

List templates

curl -s "$API/v1/templates" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" | jq

Create share

curl -s -X POST "$API/v1/shares" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "templateId": "'"$TEMPLATE_ID"'", "payload": {"name":"Alice","score":4200}, "destinationUrl": "https://example.com/results", "attributionData": {"campaign":"twitter"} }' | jq

Get share

curl -s "$API/v1/shares/$SHARE_ID" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" | jq

Force re-render

curl -s -X POST "$API/v1/shares/$SHARE_ID/render" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" | jq

OG meta page (crawler)

curl -s "$API/s/$SHARE_ID" \ -H "User-Agent: Twitterbot/1.0" | grep og:

Follow redirect (human)

curl -s -L -w "\nFinal URL: %{url_effective}\n" \ "$API/s/$SHARE_ID"

Media asset – image

curl -s -L -o preview.png "$API/m/$SHARE_ID/image"

Media asset – video

curl -s -L -o preview.mp4 "$API/m/$SHARE_ID/video"

Upload asset

curl -s -X POST "$API/v1/assets" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" \ -F "file=@/path/to/image.png" | jq

List assets

curl -s "$API/v1/assets" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" | jq

Delete share

curl -s -X DELETE "$API/v1/shares/$SHARE_ID" \ -H "x-organisation-id: $ORG" \ -H "Authorization: Bearer $TOKEN" \ -w "HTTP %{http_code}"

Reject unauthenticated request

curl -s -w "\nHTTP %{http_code}" "$API/v1/templates"

DDC - View lineup card

export DDC_ORG="real-madrid-mens" export FIXTURE="2m4sef2l4im49rda90k3p41lg" curl -s -o lineup.jpg "$API/ddc/$DDC_ORG/lineup/$FIXTURE.jpg" open lineup.jpg

DDC - Force cache refresh

curl -s -o lineup.jpg \ "$API/ddc/$DDC_ORG/lineup/$FIXTURE.jpg?refresh=1"

DDC - External data source (POST - Studio)

# POST - as Studio would call it (orgSlug in body) curl -s -X POST "$API/ddc/lineup/source" \ -H "Content-Type: application/json" \ -d '{ "project_id": "proj-001", "project": { "custom_fields": { "hypecard_orgSlug": "'"$DDC_ORG"'" } }, "element": { "content_type": "hypecard-element", "custom_fields": {} } }' | jq '.items | length'

DDC - External data source (GET - direct)

# GET - direct access, orgSlug in URL path curl -s "$API/ddc/$DDC_ORG/lineup/source" | jq '.items | length' # Show first item curl -s "$API/ddc/$DDC_ORG/lineup/source" | jq '.items[0]' # Check Cache-Control (should be no-store) curl -sI "$API/ddc/$DDC_ORG/lineup/source" | grep -i cache-control

DDC - Get player names

curl -s "$API/ddc/$DDC_ORG/players/names" | jq

DDC - Update short names

curl -s -X PATCH "$API/ddc/$DDC_ORG/config" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "playerNames": { "Vinícius Júnior": "Vini Jr", "K. Mbappé": "Mbappé", "T. Alexander-Arnold": "T. Arnold" } }' | jq

DDC - Remove short name override

curl -s -X PATCH "$API/ddc/$DDC_ORG/config" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"remove": ["T. Alexander-Arnold"]}' | jq

DDC - Upload player headshot

curl -s -X POST "$API/ddc/$DDC_ORG/players/p123456/image" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: image/jpeg" \ --data-binary @headshot.jpg | jq
RESPONSE LOG