Publish a project component
Publishes a ready version of one of the project's own components to the organization's registry, sharing its module and editor panel.
Guide: Publishing
A project secret key: vh_sk_... for production, vh_sk_test_... for test. Keep it on your servers.
In: header
Path parameters
The project's id, proj_.... A secret key works only in the project it belongs to.
Request body
application/json
TypeScript definitions
Use the request body type in TypeScript.
The id of the project component version to publish, cmp_ver_...; it must be ready.
The semantic version to publish it as.
The registry name, the second part of <publisher>/<name>; defaults to the component's slug.
The name people see; defaults to the project component's title.
What the component does; defaults to the module definition's description.
The editor group; defaults to the project component's category.
Words people can search for the component by; defaults to none.
Examples
curl -X POST "https://api.voidhash.com/api/v1/projects/proj_tz4a98xxat96iws9zmbrgj3a/registry-components/promotions" \ -H "Authorization: Bearer vh_sk_..." \ -H "Content-Type: application/json" \ -d '{ "componentVersionId": "cmp_ver_k3m8x2c7v9b4n1q6w5e0r8t2", "version": "1.0.0", "keywords": [ "plans", "pricing" ] }'{ "id": "cmp_pkg_ver_m1q5w9e3r7t1y5u9i3o7p1a5", "registryComponentId": "cmp_pkg_h2j7k4l9z1x6c3v8b5n0m4q7", "version": "1.0.0", "number": 1, "status": "ready", "statusMessage": null, "bundleHash": "4a8c2e6f0b3d7a1c5e9f2b6d0a4c8e3f7b1d5a9c2e6f0b4d8a3c7e1f5b9d2a6c", "contentHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "byteSize": 58912, "capabilities": [ "commerce" ], "definition": { "id": "acme/plan-picker", "version": "1.0.0", "title": "Plan picker", "description": "Selectable plans.", "icon": { "kind": "builtin", "name": "component" }, "category": "", "keywords": [ "plans", "pricing" ], "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" } }, "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" } }, "hasPanel": false, "hasIcon": false, "hasReadme": false, "hasAgentGuide": false, "thumbnailStates": [], "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": [] } ] }, "installCount": 0, "publishedPaywallCount": 0, "createdBy": "user_k3m8q1z6v9c2x5b7n4w0e8r1", "publishedAt": "2026-03-05T10:12:00.000Z"}{ "error": { "type": "invalid_request", "code": "invalid_component_version", "message": "The component version cannot be published. The definition version \"1.3\" is not a semantic version such as 1.0.0.", "param": "componentVersionId" }}{ "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": "conflict", "code": "publisher_required", "message": "The organization has no component namespace yet. An organization admin must claim a namespace (for example `acme`) before components can be published." }}{ "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." }}{ "error": { "type": "unavailable", "code": "component_checks_unavailable", "message": "The conformance checks could not run, so nothing was published. Try again in a moment." }}Response body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
Errors
| Status | type | code | When |
|---|---|---|---|
| 400 | invalid_request | invalid_component_version | , and like publishing a bundle with. |
| 400 | invalid_request | conformance_failed | , and like publishing a bundle with. |
| 404 | not_found | component_version_not_found | Unless the version is ready and its component exists. |
| 409 | conflict | publisher_required | — |
| 409 | conflict | version_already_published | — |
| 503 | unavailable | component_checks_unavailable | — |
It can also fail with the errors every operation shares, such as unauthenticated; see Errors.
More in Component registry
- Retrieve the registry publisher
GET - Claim a registry namespace
PUT - List registry components
GET - Publish a component bundle
POST - Retrieve a registry component
GET - Update a registry component
PATCH - List a registry component's versions
GET - Retrieve a registry component version
GET - Update a registry component version
PATCH - Retrieve a version's file
GET - Review an install
GET - List installed components
GET - Install a registry component
POST - Retrieve an install
GET - Update an install
PATCH - Uninstall a registry component
DELETE
Something wrong or missing on this page? Tell us by email or on Discord.