
Gen Paylink Govilo
- 3k installs
- 1 repo stars
- Updated February 13, 2026
- hau823823/govilo-to-go
This is a copy of gen-paylink-govilo by hau823823 - installs and ranking accrue to the original listing.
gen-paylink-govilo is a Govilo automation skill that uploads files to R2 via presigned URLs and creates crypto-paid unlock links for developers selling digital artifacts through the Govilo Bot API.
About
gen-paylink-govilo is a skill (v1.0) in hau823823/govilo-to-go that uploads files to Govilo and generates unlock links via the Bot API. The workflow covers presign, upload to Govilo R2 storage, and create item for a ZIP, folder, or individual files. Required environment variables are GOVILO_API_KEY and SELLER_ADDRESS; the skill guides registration at govilo.xyz when keys are missing. Developers reach for gen-paylink-govilo when automating paid file drops, packaging release artifacts behind crypto unlock links, or scripting Govilo Bot API interactions without manual dashboard steps. The skill is tagged for OpenClaw with GOVILO_API_KEY as the primary env var.
- One-command workflow: package → upload to R2 → generate paid unlock link
- Automates full Govilo Bot API sequence (presign, upload, create item)
- Always prompts for title, price (USDC), and description before running
- Guides user to register and set GOVILO_API_KEY + SELLER_ADDRESS when missing
Gen Paylink Govilo by the numbers
- 3,002 all-time installs (skills.sh)
- Security screen: CRITICAL risk (skills.sh audit)
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hau823823/govilo-to-go --skill gen-paylink-goviloAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3k |
|---|---|
| repo stars | ★ 1 |
| Security audit | 2 / 3 scanners passed |
| Last updated | February 13, 2026 |
| Repository | hau823823/govilo-to-go ↗ |
How do you create a paid Govilo unlock link?
Instantly turn any file, folder or ZIP into a paid Govilo unlock link that collects crypto payments.
Who is it for?
Developers distributing paid ZIPs, folders, or file bundles who already have Govilo API credentials and a seller wallet address.
Skip if: Teams needing fiat checkout, subscription billing, or file sales outside the Govilo crypto unlock model.
When should I use this skill?
The user wants a Govilo unlock link from files, needs presigned R2 upload automation, or asks to script Govilo Bot API item creation.
What you get
Govilo unlock link, uploaded R2 object, and created sellable item record.
- govilo unlock link
- uploaded file on R2
By the numbers
- Ships at version 1.0 in the govilo-to-go manifest
- Requires 2 environment variables: GOVILO_API_KEY and SELLER_ADDRESS
Files
Govilo To Go
Turn any file into a paid unlock link — one command to package, upload, and collect crypto payments. The last mile of automation: from creation to monetization.
Before Running
Always ask the user for these values before executing the CLI — never guess or use placeholders:
1. title — What is the product name? 2. price — How much to charge (in USDC)? 3. description — Short description of the product (optional, but always ask)
CLI Command
Requires uv. See references/setup-guide.md for install instructions.
Run from this skill's base directory. Use a dedicated env file containing only GOVILO_API_KEY (and optionally SELLER_ADDRESS). Never point --env-file at a project .env that contains unrelated secrets.
cd <skill_base_directory>
uv run --env-file <path_to>/.env.govilo create-link \
--input <path> \
--title "Product Name" \
--price "5.00" \
--address "0x..." \
--description "optional"If no .env.govilo exists, create one before running:
GOVILO_API_KEY=sk_live_xxx
SELLER_ADDRESS=0x...--input accepts ZIP file, folder, or individual files (repeatable). Non-ZIP inputs are auto-packaged.
All output is JSON {"ok": true/false, ...} with exit code 1 on failure.
Parameters
| Param | Required | Source | Description |
|---|---|---|---|
--input | Yes | CLI (repeatable) | ZIP, folder, or file paths |
--title | Yes | CLI | Product title |
--price | Yes | CLI | Price in USDC |
--address | No | CLI > SELLER_ADDRESS env | Seller EVM wallet |
--description | No | CLI | Product description |
Workflow
1. Validate config (API Key + seller address) 2. Package inputs → ZIP (if not already ZIP) 3. POST /api/v1/bot/uploads/presign → get upload_url + session_id 4. PUT upload_url → upload ZIP to R2 5. POST /api/v1/bot/items → get unlock_url
File Limits
- Max ZIP size: 20 MB
- Max files in ZIP: 20
Setup
Two values are required:
| Variable | Required | Description |
|---|---|---|
GOVILO_API_KEY | Yes | Bot API key from [govilo.xyz][] |
SELLER_ADDRESS | Yes* | EVM wallet address on Base chain |
[govilo.xyz]: https://govilo.xyz/
*SELLER_ADDRESS can also be passed via --address CLI parameter.
See references/setup-guide.md for step-by-step registration and wallet setup instructions.
API Reference
See references/bot-api-quick-ref.md for Bot API endpoints and error codes.
[project]
name = "govilo-to-go"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["requests"]
[project.scripts]
create-link = "scripts.workflow_create:main"
[project.optional-dependencies]
dev = ["pytest"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["scripts"]
[tool.pytest.ini_options]
testpaths = ["tests"]
Bot API Quick Reference
Base URL: https://api.unlock.govilo.xyz
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/v1/bot/uploads/presign | Bearer sk_live_xxx | Get presigned upload URL |
| POST | /api/v1/bot/items | Bearer sk_live_xxx | Confirm upload and create item |
Presign Request
POST /api/v1/bot/uploads/presign
{"seller_address": "0x..."}Response: upload_url, session_id, object_path, expires_at
Upload
PUT <upload_url>
Content-Type: application/zip
Body: <raw ZIP bytes>Create Item Request
POST /api/v1/bot/items
{"session_id": "...", "title": "...", "price": "5.00", "description": "..."}Response: id, unlock_url, file_count, total_size, upload_status
Error Codes
| Code | HTTP | Message |
|---|---|---|
| 809108001 | 401 | invalid api key |
| 809108002 | 401 | api key has been revoked |
| 809108003 | 401 | api key has expired |
| 809108005 | 429 | daily api key usage limit exceeded |
| 809108006 | 429 | api key rate limit exceeded |
| 809104001 | 404 | upload session not found |
| 809104002 | 410 | upload session expired |
| 809104003 | 404 | file not found |
Setup Guide
Prerequisites
This skill requires uv — a fast Python package manager and runner.
Install uv
macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Or via Homebrew
brew install uv
uv run automatically resolves Python >=3.11 and the requests dependency from pyproject.toml — no manual pip install needed.
Required Values
Two values are required before using this tool:
GOVILO_API_KEY— Bot API authentication tokenSELLER_ADDRESS— Your wallet address on Base chain
1. API Key
Get Your API Key
1. Go to https://govilo.xyz/ 2. Sign up for an account (Gmail auth login) 3. Open the left sidebar menu → click Settings 4. Scroll to the API Key section → click Manage API Key 5. Create a new key and copy it (format: sk_live_xxx)
Configure
Create a dedicated env file (e.g. .env.govilo) containing only Govilo credentials:
.env.govilo
GOVILO_API_KEY=sk_live_xxx
Important: Do not use a shared project .env that may contain unrelated secrets.Always use a dedicated file like .env.govilo to avoid accidental leakage.Verify
cd skills/gen-paylink-govilo uv run --env-file .env.govilo create-link --help
If the key is missing or invalid, the tool outputs:
{"ok": false, "error": "API Key not configured. ..."}
2. Seller Address
Requirements
- Chain: Base (Base Mainnet only, Chain ID: 8453)
- Format: EVM address —
0x+ 40 hex characters - Example:
0x1234567890abcdef1234567890abcdef12345678
Get Your Address
MetaMask:
1. Install MetaMask browser extension (https://metamask.io/) 2. Create or import a wallet 3. Switch network to Base (add if not listed: Chain ID 8453, RPC https://mainnet.base.org) 4. Click the account name at the top to copy your address
Coinbase Wallet:
1. Install Coinbase Wallet (https://www.coinbase.com/wallet) 2. Create or import a wallet 3. Switch network to Base 4. Tap Receive → copy your address
Configure
Option A — Environment variable (recommended for repeated use):
Add to your .env.govilo file:
SELLER_ADDRESS=0xYourWalletAddress
Option B — CLI parameter (per-command override):
create-link --address "0xYourWalletAddress" ...
CLI --address takes priority over SELLER_ADDRESS env var.
Tip: You can also set a Default Payout Address on the Govilo website
(Settings → Default Payout Address → paste your 0x... address → Save).This address is pre-filled when creating new links on the web UI, but the CLI
still requiresSELLER_ADDRESSenv var or--addressparameter.
from pathlib import Path
import requests
class ApiError(Exception):
def __init__(self, message: str, code: int | None = None):
super().__init__(message)
self.code = code
class GoviloClient:
def __init__(self, api_key: str, base_url: str):
self._base_url = base_url.rstrip("/")
self._headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
def _check_response(self, resp: requests.Response) -> dict:
body = resp.json()
if body.get("code", 0) != 0:
raise ApiError(body.get("msg", "unknown error"), body.get("code"))
return body["data"]
def presign(self, seller_address: str) -> dict:
resp = requests.post(
f"{self._base_url}/api/v1/bot/uploads/presign",
headers=self._headers,
json={"seller_address": seller_address},
)
return self._check_response(resp)
def upload(self, upload_url: str, zip_path: Path) -> None:
with open(zip_path, "rb") as f:
resp = requests.put(
upload_url,
headers={"Content-Type": "application/zip"},
data=f,
)
if resp.status_code != 200:
raise ApiError(f"Upload failed: HTTP {resp.status_code}")
def create_item(
self,
session_id: str,
title: str,
price: str,
description: str = "",
) -> dict:
resp = requests.post(
f"{self._base_url}/api/v1/bot/items",
headers=self._headers,
json={
"session_id": session_id,
"title": title,
"price": price,
"description": description,
},
)
return self._check_response(resp)
from dataclasses import dataclass
import os
BASE_URL = "https://api.unlock.govilo.xyz"
class ConfigError(Exception):
pass
@dataclass(frozen=True)
class Config:
api_key: str
seller_address: str
base_url: str = BASE_URL
def load_config(
cli_api_key: str | None = None,
cli_address: str | None = None,
) -> Config:
api_key = cli_api_key or os.environ.get("GOVILO_API_KEY")
if not api_key:
raise ConfigError(
"API Key not configured. See references/setup-guide.md for registration steps. "
"Register at https://govilo.xyz/ then set GOVILO_API_KEY=sk_live_xxx"
)
seller_address = cli_address or os.environ.get("SELLER_ADDRESS")
if not seller_address:
raise ConfigError(
"Seller address required (Base chain). Use --address 0x... or set SELLER_ADDRESS env var. "
"See references/setup-guide.md for wallet setup"
)
return Config(api_key=api_key, seller_address=seller_address)
import tempfile
import zipfile
from pathlib import Path
MAX_ZIP_SIZE = 20 * 1024 * 1024 # 20 MB
MAX_FILE_COUNT = 20
class PackageError(Exception):
pass
def _validate_zip(zp: Path) -> None:
if zp.stat().st_size > MAX_ZIP_SIZE:
raise PackageError(f"ZIP file exceeds 20 MB limit")
with zipfile.ZipFile(zp) as zf:
if len(zf.namelist()) > MAX_FILE_COUNT:
raise PackageError(f"ZIP contains more than {MAX_FILE_COUNT} files")
def _zip_paths(paths: list[Path], dest: Path) -> None:
with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as zf:
for p in paths:
zf.write(p, p.name)
def package(inputs: list[str]) -> Path:
paths = [Path(p) for p in inputs]
for p in paths:
if not p.exists():
raise PackageError(f"Path not found: {p}")
# Single .zip file — passthrough
if len(paths) == 1 and paths[0].suffix == ".zip":
_validate_zip(paths[0])
return paths[0]
# Single directory — zip its contents
if len(paths) == 1 and paths[0].is_dir():
files = [f for f in paths[0].rglob("*") if f.is_file()]
if len(files) > MAX_FILE_COUNT:
raise PackageError(f"Directory contains more than {MAX_FILE_COUNT} files")
dest = Path(tempfile.mktemp(suffix=".zip"))
with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as zf:
for f in files:
zf.write(f, f.relative_to(paths[0]))
_validate_zip(dest)
return dest
# Multiple files — zip them together
if len(paths) > MAX_FILE_COUNT:
raise PackageError(f"Input exceeds {MAX_FILE_COUNT} files limit")
dest = Path(tempfile.mktemp(suffix=".zip"))
_zip_paths(paths, dest)
_validate_zip(dest)
return dest
import argparse
import json
import sys
from pathlib import Path
from scripts.api_client import GoviloClient, ApiError
from scripts.config import load_config, ConfigError
from scripts.packager import package, PackageError
def _output(data: dict) -> None:
print(json.dumps(data, ensure_ascii=False))
def _fail(error: str, code: int | None = None) -> None:
out = {"ok": False, "error": error}
if code is not None:
out["code"] = code
_output(out)
sys.exit(1)
def main() -> None:
parser = argparse.ArgumentParser(description="Upload files and create Govilo unlock link")
parser.add_argument("--input", required=True, action="append", dest="inputs", help="ZIP, folder, or file path (repeatable)")
parser.add_argument("--title", required=True, help="Product title")
parser.add_argument("--price", required=True, help="Price in USDC (e.g. 5.00)")
parser.add_argument("--address", default=None, help="Seller EVM wallet address (overrides SELLER_ADDRESS env)")
parser.add_argument("--description", default="", help="Product description")
args = parser.parse_args()
try:
cfg = load_config(cli_api_key=None, cli_address=args.address)
except ConfigError as e:
_fail(str(e))
try:
zip_path = package(args.inputs)
except PackageError as e:
_fail(str(e))
is_temp = zip_path not in [Path(p) for p in args.inputs]
try:
client = GoviloClient(api_key=cfg.api_key, base_url=cfg.base_url)
try:
presign_data = client.presign(cfg.seller_address)
client.upload(presign_data["upload_url"], zip_path)
item_data = client.create_item(
session_id=presign_data["session_id"],
title=args.title,
price=args.price,
description=args.description,
)
except ApiError as e:
_fail(str(e), code=e.code)
_output({
"ok": True,
"unlock_url": item_data["unlock_url"],
"item_id": item_data["id"],
"file_count": item_data["file_count"],
"total_size": item_data["total_size"],
})
finally:
if is_temp:
zip_path.unlink(missing_ok=True)
Related skills
FAQ
What environment variables does gen-paylink-govilo need?
gen-paylink-govilo requires GOVILO_API_KEY and SELLER_ADDRESS. If either is missing, the skill directs developers to register at https://govilo.xyz/ before running the presign-upload-create flow.
What inputs does gen-paylink-govilo accept?
gen-paylink-govilo creates unlock links from a ZIP archive, a folder, or individual files. The skill automates presigned upload to Govilo R2 storage and item creation through the Govilo Bot API.
Is Gen Paylink Govilo safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.