Skip to content

Web App - User Guide

CodeFetch is a secure, encrypted script library hosted in the cloud. You publish scripts to your private library, retrieve and search them from any machine, and share individual scripts publicly via signed links — all without the server ever seeing your file contents in plaintext.

New to CodeFetch? Start with Getting Started for the full account → extension → CLI walkthrough. This guide documents the web app's underlying API in detail — useful once you're set up and want to script account operations, or understand exactly what a web app button does.


Getting Started

Sign Up

CodeFetch uses email verification — no password required.

  1. Send a signup request:
curl -s -X POST "https://app.codefetch.io/api/request-signup-code" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com"}'
  1. Check your email for a 6-digit code, then verify it:
curl -s -X POST "https://app.codefetch.io/api/verify-signup-code" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "code": "123456"}'

The response contains your tenantId and secret:

{
  "ok": true,
  "tenantId": "550e8400-e29b-41d4-a716-446655440000",
  "secret": "base64-encoded-secret"
}

Save both immediately. The secret is returned once only and cannot be recovered — it is never stored on the server. Lose it and you lose access to your library.


Your Two Credentials

Credential What it is When you use it
tenantId Your UUID — identifies your library in every URL Part of every API path
secret Your encryption and authentication key Publishing, deleting, migrating, getting tokens

Set them as shell variables for convenience:

export BASE_URL="https://app.codefetch.io"
export TENANT_ID="550e8400-e29b-41d4-a716-446655440000"
export SECRET="your-secret-here"

Get a Session Token

Most read operations (listing, searching, retrieving files) require a short-lived session token rather than your secret. Tokens expire after 24 hours.

TOKEN=$(curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/auth" \
  -H "Content-Type: application/json" \
  -d "{\"secret\":\"${SECRET}\"}" \
  | grep -o '"token":"[^"]*"' | cut -d'"' -f4)

Use the token as a Bearer header on requests that need it:

-H "Authorization: Bearer ${TOKEN}"

Managing Your Library

Publish a Script

Content must be base64-encoded before sending. Your secret is used directly — no token needed for publishing.

CONTENT=$(base64 -w 0 my-script.sh)   # Linux
# CONTENT=$(base64 -b 0 my-script.sh)  # macOS

curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/publish" \
  -H "Content-Type: application/json" \
  -d "{
    \"id\": \"my-script\",
    \"content\": \"${CONTENT}\",
    \"extension\": \".sh\",
    \"filename\": \"my-script.sh\",
    \"secret\": \"${SECRET}\",
    \"description\": \"My deployment script\",
    \"tags\": [\"deploy\", \"linux\"],
    \"author\": \"Jane\"
  }"
Field Required Notes
id Yes Unique identifier for this script — used in all future operations
content Yes Base64-encoded file content
extension Yes e.g. .sh, .ps1, .py
filename Yes Original filename (display only)
secret Yes Your tenant secret
description No Short summary shown in search results
tags No Array of strings for search filtering
author No Author name

Publishing with an existing id updates the script. If the content has changed, any active shared link for that script is invalidated.


List Your Library

curl -s "${BASE_URL}/${TENANT_ID}/CodeFetch-Library.json" \
  -H "Authorization: Bearer ${TOKEN}"

Returns a JSON array of all scripts with their metadata — IDs, filenames, tags, descriptions. File content is not included.


Search by Tag

curl -s "${BASE_URL}/${TENANT_ID}/api/search?tags=deploy" \
  -H "Authorization: Bearer ${TOKEN}"

Supply a comma-separated list of tags. Matching is substring-based — dep matches deploy. Omit tags entirely to return all scripts.

# Multiple tags
curl -s "${BASE_URL}/${TENANT_ID}/api/search?tags=deploy,linux" \
  -H "Authorization: Bearer ${TOKEN}"

# All scripts
curl -s "${BASE_URL}/${TENANT_ID}/api/search" \
  -H "Authorization: Bearer ${TOKEN}"

Retrieve a Script

curl -s "${BASE_URL}/${TENANT_ID}/library/my-script.sh" \
  -H "Authorization: Bearer ${TOKEN}"

Returns the raw encrypted file content. The CodeFetch CLI decrypts this automatically using your secret — if you're calling the API directly you will need to decrypt it client-side.


Update a Filename

To rename a script's display filename without changing its content:

curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/update" \
  -H "Content-Type: application/json" \
  -d "{\"id\": \"my-script\", \"filename\": \"new-name.sh\", \"secret\": \"${SECRET}\"}"

This updates the library metadata only. The script id and stored file are unchanged.


Delete a Script

curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/delete" \
  -H "Content-Type: application/json" \
  -d "{\"id\": \"my-script\", \"secret\": \"${SECRET}\"}"

Removes the file from storage and from the library index. Any shared link for this script will return 404.


Shared links let you share a script publicly — anyone with the link URL can read the content, without needing your secret or a session token.

Shared links use a separate encryption key derived from a signature you control, not your tenant secret. The server stores the content re-encrypted with that signature — it cannot decrypt it without the signature in the URL.

Shared link creation requires the content to be re-encrypted client-side with the share signature before sending. This is handled automatically by the CodeFetch CLI and web frontend. If calling the API directly:

curl -s -X POST "${BASE_URL}/api/create-link" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d "{
    \"tenantId\": \"${TENANT_ID}\",
    \"scriptPath\": \"library/my-script.sh\",
    \"encryptedContent\": \"<content re-encrypted with signature>\"
  }"

There is one link per script — creating a new link for the same script replaces the previous one.

https://app.codefetch.io/links/{tenantId}/{scriptId}?sig={signature}

No auth required. The sig parameter is the decryption key — without it the content cannot be read.

curl -s "${BASE_URL}/api/list-links" \
  -H "Authorization: Bearer ${TOKEN}"

The response includes an invalidated flag per link. A link becomes invalidated when the script content is updated — the old encrypted content no longer matches. Create a new link to restore sharing.

curl -s -X POST "${BASE_URL}/api/delete-link" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d "{\"tenantId\": \"${TENANT_ID}\", \"linkToken\": \"my-script\"}"

Quota & Limits

Limit Free (trial) Individual Team Enterprise
File count 100 500 1,500 2,500
Storage 100 MB 500 MB 1,500 MB 2,500 MB

Storage limit tracks file count at a fixed 1 MB per file. File count is checked on new publishes only — updating an existing script does not count against the limit. Storage is tracked incrementally; deleting files frees up quota immediately.

If you hit either limit, publish returns 403 with details of the limit reached.

Limits and pricing are configured server-side and can change — the table above reflects current defaults, not a fixed contractual price. Check the plan panel in the web app for your account's actual current limits.


Billing

Your plan, storage usage, and trial/renewal status are shown in the plan panel at the top of the web app. Click Manage subscription to open your account on our billing partner's site, where you can view invoices, update payment details, upgrade or downgrade your tier, and manage or cancel your subscription — purchasing and plan changes all happen there, not in the CodeFetch app itself.


Downloads

The web app provides direct download links for the tools that connect to your library:

  • The VS Code extension .vsix (for manual install without the Marketplace — see the VS Code Extension guide)
  • The CLI install scripts for Linux, macOS, and Windows (see the CLI guide)

Changing Your Secret

Rotating your secret is a multi-step process — the web UI walks you through it (open the "Change Secret" modal), or you can drive it directly via the API. Your files are re-encrypted under both the old and new secret during the process, and the switch to the new secret only happens after every file has been verified to decrypt correctly under it — so nothing in your library is ever at risk partway through, and there's no separate backup step to opt into.

New secret requirements: 12–128 characters, must contain at least one letter and one number or special character, and must differ from your current secret.

# 1. Start the rotation
curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/rotation/start" \
  -H "Content-Type: application/json" \
  -d "{\"currentSecret\": \"${SECRET}\", \"newSecret\": \"myNewSecret456!\"}"

# 2. Migrate files in batches — repeat until "remaining" is 0
curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/rotation/step" \
  -H "Content-Type: application/json" \
  -d "{\"currentSecret\": \"${SECRET}\"}"

# 3. Verify every file decrypts under the new secret
curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/rotation/verify" \
  -H "Content-Type: application/json" \
  -d "{\"newSecret\": \"myNewSecret456!\"}"

# 4. Switch to the new secret — the one irreversible step
curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/rotation/cutover" \
  -H "Content-Type: application/json" \
  -d "{\"newSecret\": \"myNewSecret456!\"}"

# 5. Clean up the old-secret copies — repeat until "done" is true
curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/rotation/cleanup" \
  -H "Content-Type: application/json"

After step 4 (cutover), your old secret no longer works. You can check progress at any point with GET /{tenantId}/api/rotation/status.


Account Management

Change Email

# Step 1 — request a code (sent to your current email)
curl -s -X POST "${BASE_URL}/api/request-email-change-code" \
  -H "Content-Type: application/json" \
  -d "{\"tenantId\": \"${TENANT_ID}\", \"newEmail\": \"new@example.com\"}"

# Step 2 — confirm with the code
curl -s -X POST "${BASE_URL}/${TENANT_ID}/api/change-email" \
  -H "Content-Type: application/json" \
  -d "{\"newEmail\": \"new@example.com\", \"code\": \"123456\", \"secret\": \"${SECRET}\"}"

Delete Your Account

Account deletion is permanent and irreversible — all files and metadata are removed. In the web app this is a single Settings → Delete Account button, which sends you an email confirmation code before actually deleting anything — the two-step API calls below are what that button does under the hood.

# Step 1 — request a deletion code (sent to your email)
curl -s -X POST "${BASE_URL}/api/request-delete-tenant-code" \
  -H "Content-Type: application/json" \
  -d "{\"tenantId\": \"${TENANT_ID}\"}"

# Step 2 — confirm with the code
curl -s -X POST "${BASE_URL}/api/delete-tenant" \
  -H "Content-Type: application/json" \
  -d "{\"tenantId\": \"${TENANT_ID}\", \"code\": \"123456\"}"

Shorty URL Shortener

If you have a Shorty instance, you can configure CodeFetch to register a short URL whenever you create a shared link (e.g. https://codefet.ch/my-script alongside the full shared link URL).

Shorty credentials are stored encrypted on the server — CodeFetch never sees your API key or URL in plaintext.

Configuration is done via the CodeFetch CLI or web frontend, which encrypt the credentials client-side before sending.