VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Essentials
API overview
Authentication
Event capture
Push device API
Webhooks
Webhook delivery
Webhook events
Projects & keys
Projects
API keys
Audit log
Customers & access
Persons
Products
Perks
Sandbox
Paywalls
Paywalls
Paywall locations
Components
Component registry
Assets
Experiments & flags
Experiments
Feature flags
Analytics & events
Analytics
Analytics alerts
Events
Ingest policy
VoidQL
Tracking domains
Ads
Ads
Ad accounts
Meta measurement
Payments & stores
Payment providers
Payment provider products
Purchase history imports
Payment sources
Webhooks & notifications
Webhooks
Push notifications
Push configurations
Automations
Organization & team
Organizations
Members
Invitations
Billing
Your account
Profile
Session
Notices
Connected apps
Terms of Service
Developer tools
Schema
SDK
List components
Upload a component module
Submit a component's source
Retrieve a component
Update a component
Delete a component
List a component's versions
Retrieve a component version
Update a component version
List component uses

Retrieve a component version

Reads one version with its build status, build log and, for Rust sources, its crate files.

Versions stay readable after their component is deleted, since published paywalls may still embed them.

Guide: Components

GET
/api/v1/projects/{projectId}/components/{componentId}/versions/{versionId}

Authorization

AuthorizationBearer <token>

A project secret key: vh_sk_... for production, vh_sk_test_... for test. Keep it on your servers.

In: header

Path parameters

projectId*string

The project's id, proj_.... A secret key works only in the project it belongs to.

componentId*string

The component's id, cmp_....

versionId*string

The id of the component's version, cmp_ver_....

Examples

curl -X GET "https://api.voidhash.com/api/v1/projects/proj_tz4a98xxat96iws9zmbrgj3a/components/cmp_p4z7c1x9v3b8n2m6q5w0e4r7/versions/cmp_ver_k3m8x2c7v9b4n1q6w5e0r8t2" \  -H "Authorization: Bearer vh_sk_..."
{  "id": "cmp_ver_k3m8x2c7v9b4n1q6w5e0r8t2",  "componentId": "cmp_p4z7c1x9v3b8n2m6q5w0e4r7",  "version": 3,  "sourceKind": "rust",  "status": "ready",  "contentHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",  "panelHash": null,  "byteSize": 58912,  "manifest": {    "id": "project/plan-picker",    "version": "0.1.0",    "title": "Plan picker",    "description": "Selectable plans.",    "icon": {      "kind": "builtin",      "name": "component"    },    "category": "Project",    "keywords": [],    "implementation": {      "kind": "wasm",      "abi": 2    },    "traits": {      "frame": {        "resize": "width"      },      "appearance": {},      "effects": {}    },    "children": {      "kind": "none"    },    "props": [      {        "name": "plans",        "type": {          "kind": "list",          "of": {            "kind": "product"          }        },        "default": []      },      {        "name": "accent",        "type": {          "kind": "color"        },        "default": "#7c3aed"      }    ],    "events": [      {        "name": "selected",        "payload": [          {            "name": "productId",            "type": {              "kind": "string"            }          }        ]      }    ],    "previewStates": [      "default"    ],    "capabilities": [      "commerce"    ],    "panel": false,    "fallback": "placeholder",    "defaultSize": {      "width": "fill",      "height": "hug"    }  },  "isDeprecated": false,  "deprecatedAt": null,  "warnings": [],  "conformance": {    "hasPassed": true,    "checks": [      {        "name": "module",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "manifest",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "imports",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "exports",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "lifecycle",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "values",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "tree",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "determinism",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "events",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "timers",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "layout",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "actions",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "frames",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "memory",        "status": "pass",        "errors": [],        "warnings": []      },      {        "name": "golden",        "status": "skip",        "errors": [],        "warnings": []      }    ]  },  "createdBy": "user_k3m8q1z6v9c2x5b7n4w0e8r1",  "createdAt": "2026-03-04T16:20:00.000Z",  "builtAt": "2026-03-04T16:21:12.000Z",  "buildLog": "   Compiling plan-picker v0.1.0 (/build)\n    Finished `release` profile [optimized] target(s) in 41.27s\n",  "sourceFiles": {    "src/lib.rs": "#![no_std]\n\nuse voidhash_ui::prelude::*;\n\n/// Selectable plans: tapping one selects it, and the button buys it.\n#[component(\n    title = \"Plan picker\",\n    description = \"Selectable plans.\",\n    events(selected(product_id: string)),\n    capabilities(commerce),\n    traits(frame(resize = \"width\"), appearance, effects),\n    size(width = \"fill\", height = \"hug\")\n)]\npub fn PlanPicker(cx: Cx, plans: Vec<Product>, #[prop(default = \"#7c3aed\")] accent: Color) -> View {\n    let selected = cx.state(|| plans.first().map(|plan| plan.id.clone()));\n    let current = selected.get();\n    vstack()\n        .spacing(12)\n        .children(plans.iter().map(|plan| {\n            let id = plan.id.clone();\n            hstack()\n                .key(&plan.id)\n                .child(text(&plan.title).font(Font::HEADLINE))\n                .child(spacer())\n                .child(text(plan.price_per_period()))\n                .border(if current.as_ref() == Some(&plan.id) { 2 } else { 1 }, accent)\n                .corner_radius(14)\n                .on_tap(move |cx| {\n                    selected.set(Some(id.clone()));\n                    cx.emit(\"selected\", object([(\"productId\", Value::from(&id))]))\n                })\n        }))\n        .child(button(\"Continue\").prominent().on_tap(move |cx| {\n            if let Some(id) = selected.get() {\n                cx.purchase(&id);\n            }\n        }))\n}\n"  }}
{  "error": {    "type": "invalid_request",    "code": "string",    "message": "string",    "param": "string"  }}
{  "error": {    "type": "unauthenticated",    "code": "invalid_api_key",    "message": "This secret key is not valid."  }}
{  "error": {    "type": "permission_denied",    "code": "permission_denied",    "message": "Insufficient permissions."  }}

{  "error": {    "type": "not_found",    "code": "component_version_not_found",    "message": "This component has no version cmp_ver_k3m8x2c7v9b4n1q6w5e0r8t2.",    "param": "versionId"  }}

{  "error": {    "type": "internal",    "code": "internal_error",    "message": "Something went wrong on our side. Try again, and contact support with the Request-Id header if it keeps failing."  }}

Response body

application/json

application/json

application/json

application/json

application/json

application/json

Errors

StatustypecodeWhen
404not_foundcomponent_version_not_found—

It can also fail with the errors every operation shares, such as unauthenticated; see Errors.

More in Components

  • List components GET
  • Upload a component module POST
  • Submit a component's source POST
  • Retrieve a component GET
  • Update a component PATCH
  • Delete a component DELETE
  • List a component's versions GET
  • Update a component version PATCH
  • List component uses GET

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousList a component's versionsNextUpdate a component version

On this page

AuthorizationPath parametersExamplesResponse bodyErrorsMore in Components