Install
Download the canonical single-file client on macOS or Linux. Inspect the file before executing it if your environment requires source review.
set -eu
SFB_CLI_FILE='submitforbacklinks-1.1.0.mjs'
SFB_CLI_SHA256='669e7894aa7c1914d9b2e432aa05a0be87c33dc2b68edbcc6601880e385526ee'
curl -fsSL 'https://submitforbacklinks.com/downloads/submitforbacklinks/1.1.0' -o "$SFB_CLI_FILE"
node - "$SFB_CLI_FILE" "$SFB_CLI_SHA256" <<'SFB_VERIFY'
const { createHash } = require("node:crypto");
const { readFileSync } = require("node:fs");
const [file, expected] = process.argv.slice(2);
const actual = createHash("sha256").update(readFileSync(file)).digest("hex");
if (!/^[a-f0-9]{64}$/.test(expected) || actual !== expected) {
console.error("Checksum verification failed.");
process.exit(1);
}
console.log(file + ": checksum verified");
SFB_VERIFY
chmod +x "$SFB_CLI_FILE"
ln -sf "$SFB_CLI_FILE" submitforbacklinks
./submitforbacklinks --versionRuntime
The executable is a JavaScript module and requires a current Node.js runtime. It does not add a dependency to your SaaS project.
Set up terminal ownership
Run setup once and publish the exact .well-known proof on the product domain. The email receives notices; no code is sent. After verification, the CLI stores its credential with owner-only file permissions. No browser login, copied API key, or .env file is required.
./submitforbacklinks setup https://yourproduct.com \
--email [email protected]
# Publish the exact returned .well-known file, then:
./submitforbacklinks setup --verify./submitforbacklinks claimCommands
Capabilities and scan are safe discovery operations. Every submission, update, badge, list, and status operation uses the owner-scoped bearer token.
./submitforbacklinks capabilities
./submitforbacklinks scan https://yourproduct.com --pretty > scan.json
export SFB_DRAFT_KEY="$(node -e 'console.log(crypto.randomUUID())')"
./submitforbacklinks draft https://yourproduct.com \
--from-scan scan.json \
--idempotency-key "$SFB_DRAFT_KEY"
./submitforbacklinks list
./submitforbacklinks status 00000000-0000-4000-8000-000000000000 \
--pretty > reviewed-status.jsoncapabilities
Print current scopes, limits, endpoints, and canonical discovery links.
setup <url> --email <email>
Create domain proof; no email code is sent.
setup --verify
Verify the deployed proof and securely store the terminal credential.
claim
Create a 15-minute one-use link for optional dashboard editing.
scan <url>
Propose listing content without reserving the domain or creating a submission.
draft <url>
Create an owner-scoped draft; use --from-scan to preserve reviewed scan copy.
update <id>
Replace all nine reviewed fields on an editable owner-scoped submission.
submit <url>
Send a complete reviewed scan file with --from-scan and explicit confirmations.
finalize <id>
Send an existing reviewed draft with explicit confirmations.
list
List submissions owned by the configured API key; use --limit 1-100 and the prior response's --cursor value to continue.
status <id>
Retrieve one owner-scoped submission.
badge-issue <id>
Issue the exact free-listing badge markup.
badge-verify <id> <url>
Verify the badge on a public HTTPS page of the product domain.
badge-status <id>
Retrieve badge, follow-window, link-policy, and markup state.
Correct an editable submission
The normal path is scan to a file, inspect it, create a draft with --from-scan, save the exact server state with status --pretty, and update that reviewed state with --from-status if needed. A status file is bound to its submission ID. Every mutation using --from-scan validates its source hostname against the submitted website. Update with --from-scan performs an owner-scoped status preflight and needs submissions:read plus submissions:write. Update accepts either --from-status or --from-scan, never both, and optional --founder, --email, --company, --tagline, and --description flags override those values. A submitted or published working copy may return to DRAFT for re-review while its current public listing remains live. Retrieve the submission again before finalizing it.
# Edit submission fields in reviewed-status.json first.
export SFB_UPDATE_KEY="$(node -e 'console.log(crypto.randomUUID())')"
./submitforbacklinks update 00000000-0000-4000-8000-000000000000 \
--from-status reviewed-status.json \
--idempotency-key "$SFB_UPDATE_KEY"Explicit final submission
The CLI does not infer acceptance. The normal path is draft, status review, optional update, status review again, then finalize. Pass every confirmation only after the product owner has reviewed the exact saved listing. Add --week YYYY-MM-DD to request an available week, or omit it to use the next available week.
export SFB_FINALIZE_KEY="$(node -e 'console.log(crypto.randomUUID())')"
./submitforbacklinks finalize 00000000-0000-4000-8000-000000000000 \
--idempotency-key "$SFB_FINALIZE_KEY" \
--confirm-terms \
--confirm-badge \
--confirm-representative \
--confirm-reviewed./submitforbacklinks scan https://yourproduct.com --pretty > scan.json
# Inspect and, if needed, edit scan.json before continuing.
export SFB_SUBMIT_KEY="$(node -e 'console.log(crypto.randomUUID())')"
./submitforbacklinks submit https://yourproduct.com \
--from-scan scan.json \
--idempotency-key "$SFB_SUBMIT_KEY" \
--confirm-terms \
--confirm-badge \
--confirm-representative \
--confirm-reviewedAutomation boundary
- The caller accepts the Terms and Submission Guidelines.
- The caller understands the badge requirement for free dofollow treatment.
- The caller is authorized to represent the product.
- The generated content has been reviewed for accuracy.
--from-scan accepts the raw scan response containing draft. The CLI sends only the nine listing fields. Scan confidence, source URLs, and warnings remain review context; explicit tagline or description flags override the saved values.
Manage free-listing badge verification
Issue the badge, install one exact markup theme returned by the command on a public HTTPS page of the submitted domain, then verify that page. badge-status reports the saved target, failures, timestamps, active or pending follow window, link policy, and markup.
export SFB_BADGE_ISSUE_KEY="$(node -e 'console.log(crypto.randomUUID())')"
./submitforbacklinks badge-issue 00000000-0000-4000-8000-000000000000 \
--idempotency-key "$SFB_BADGE_ISSUE_KEY"
# Install one returned markup theme on the submitted product domain.
export SFB_BADGE_VERIFY_KEY="$(node -e 'console.log(crypto.randomUUID())')"
./submitforbacklinks badge-verify 00000000-0000-4000-8000-000000000000 \
https://yourproduct.com/partners \
--idempotency-key "$SFB_BADGE_VERIFY_KEY"
./submitforbacklinks badge-status 00000000-0000-4000-8000-000000000000Optional media is browser-managed
A logo and up to three screenshots are optional. Agent API v1 and this CLI do not upload or replace media.
The owner can add or manage media from the signed-in browser dashboard.
Secret handling
The CLI stores its domain-verified credential outside the project with 0600 permissions and never prints it. SUBMITFORBACKLINKS_API_KEY remains an advanced override for CI and team automation; keep overrides in a secret store, never command arguments, prompts, logs, or repositories.
Safe retry behavior
Generate and store a new UUID before each distinct mutating command: draft, submit, update, finalize, badge-issue, and badge-verify. The CLI rejects a mutation without that key. The first result—including a failure—is stored for the key. After a timeout, rerun only the identical command with the original key through --idempotency-key to recover the same outcome. If an error includes fields.submissionId, retrieve that submission first. Use a new key only after confirming no submission exists and correcting the cause.