Machine-readable purchase and operation recovery
Discover purchase requirements, request canonical receipts and recover a lost write response safely.
Machine-readable purchase and recovery
Read GET /v1/version and GET /v1/capabilities before using optional workflow features. Account features distinguish implemented, enabled and permitted. Product purchase policies describe draft_order and atomic_deploy separately; inspect their implemented, enabled, eligible and permitted fields. Discovery is not a reservation, customer authorization or a provider health guarantee.
Follow a product's requirements_url or options_url. requirements.atomic_deploy describes canonical input names, required flags, types and discovery sources. requiredFields and conditionalRequiredFields remain the draft order's legacy userConfig requirements. Region and server configuration are resolved by the selected SKU URL. Read the returned OS choices and your owned SSH keys; never invent codes or identifiers.
Quotes retain their existing total, breakdown and items. quote.recommended_max_total equals the quoted final tax/setup/add-on-inclusive total, in quote.currency. After authorization, send that amount as max_total. The final deployment revalidates prices and returns HTTP 409 with error.code set to deployment_price_limit_exceeded if the current total exceeds the ceiling. It does not silently charge more. quote.guaranteed=false means there is no price lock. quote.id and pricing_revision fingerprint this priced cart for correlation; they are not redeemable quote resources or global catalog revisions. links.deploy points to the atomic purchase endpoint where applicable. Quote remains optional.
A common operation receipt
For supported deployment, VPS and dedicated writes, send x-bf-response-format: operation to request the canonical Operation envelope. Check canonical_operation_responses first. The default preserves existing action/task fields and adds operation_id, operation_url and links. A cached retry preserves its initial response format; accept operation.id or operation_id, then poll links.operation or GET /v1/operations/{operationId}. No new key is needed to poll.
| Operation status | done | Meaning |
|---|---|---|
| pending, running | false | Accepted or executing; not completed |
| unknown | false | Outcome needs reconciliation; never assume failure or submit a new write |
| succeeded | true | Recorded operation completed successfully |
| failed, cancelled | true | Recorded terminal outcome; inspect billing separately |
progress may be null. stage is informational and may be null; branch on status and done. Failed operations expose a safe code/message, never raw provider errors. Only succeeded operations expose a result. Deployment results identify service_ids and, when recorded, order_id/invoice_id. Service results identify service_id and recorded OS/snapshot fields when applicable. power_state is included only when original task completion evidence provides it; present-day runtime state is a separate read. Historical receipts may lack newly introduced result fields. The first terminal receipt is immutable.
links.operation, links.service, links.invoice and links.order are relative customer API URLs, included when their resource identity is known. DNSSEC keeps its own legacy state contract and polling endpoint; its operation string/UUID is not a generic operation handle. The optional canonical adapter does not change that contract.
Recover a lost write response
GET /v1/operations?idempotency_key=original-key recovers a tracked write without repeating it. Lookup is confined to the authenticated account and its current billing.services.read, vps.read or dedicated.read permission for that operation. The same key is scoped to the original credential, HTTP method and exact path. Supply method and path together, plus credential_id if needed to disambiguate a key reused for other endpoints or credentials.
- HTTP 200: continue polling the original operation.
- HTTP 400, validation_error: correct lookup selectors; do not submit a new write.
- HTTP 404, operation_not_found: no recoverable identity found. This does not establish that the write never executed.
- HTTP 409, operation_lookup_ambiguous: supply the original method/path and, if necessary, credential_id.
- HTTP 410, operation_expired: identity remains but the receipt has expired; reconcile resources and billing.
Terminal receipts retain 90 days by default; operation_policy advertises the configured retention. Pending/unknown receipts remain for reconciliation. Lookup identities are retained indefinitely after receipt expiry and contain no raw key or credential secret. Recovery applies to newly tracked writes after this contract is enabled, not every historical request or every API write. Never generate a replacement key merely because a response or receipt was lost.
SDK recovery helpers are Python/Node/PHP operation_recover and Go OperationRecover. CLI: bf operations recover --request-key original-key --method POST --path /v1/vps/SERVICE_ID/reboot; add --wait to poll. Hosted MCP recover_operation and local MCP bf_operation_recover use the same existing key. get_operation_request tracks an MCP approval request; get_operation tracks the execution receipt. Approval acceptance is not provider completion.
New asynchronous write contracts use the common Operation envelope. Existing v1 shapes remain compatible through the opt-in adapter. Deprecated aliases are marked in OpenAPI and HTTP Deprecation metadata; no Sunset is published without a committed removal date.
Direct HTTP example
Use an issued bearer-mode credential in BF_API_BEARER. Signed-mode credentials require all HMAC headers; generic OpenAPI clients do not implement signing automatically. This read uses the exact original key, method and path:
curl --fail-with-body --get 'https://api.blazingfast.io/v1/operations' \
-H "Authorization: Bearer $BF_API_BEARER" \
--data-urlencode "idempotency_key=$ORIGINAL_REQUEST_KEY" \
--data-urlencode 'method=POST' \
--data-urlencode "path=$ORIGINAL_REQUEST_PATH"For a newly authorized, supported tracked write, send Idempotency-Key: YOUR_STABLE_WRITE_KEY and x-bf-response-format: operation to request the canonical receipt. These are separate headers: one identifies the write, the other selects its response representation. GET polling and recovery do not charge or repeat the original operation.
Native SDK examples
Configure production authentication as described in the installation guide. These examples perform a read: ORIGINAL_REQUEST_KEY is the saved key from an existing tracked write and ORIGINAL_REQUEST_PATH is its exact API path. Do not create a replacement key when recovering. The original method below is POST; use the actual method of your write. Missing or expired receipts require reconciliation, not an automatic new purchase.
Python
import os
from bf_api import BfClient
client = BfClient()
receipt = client.operation_recover(
os.environ["ORIGINAL_REQUEST_KEY"],
method="POST",
path=os.environ["ORIGINAL_REQUEST_PATH"],
)
print(receipt["operation"]["id"], receipt["operation"]["status"])For a newly authorized deployment, product_variant_deploy(region, product_code, variant_code, payload, idempotency_key=key, operation_response=True) opts into the canonical receipt.
Node.js
const { BfClient } = require('bf-api');
async function main() {
const client = new BfClient();
const receipt = await client.operation_recover(process.env.ORIGINAL_REQUEST_KEY, {
method: 'POST', path: process.env.ORIGINAL_REQUEST_PATH,
});
console.log(receipt.operation.id, receipt.operation.status);
}
main().catch((error) => { console.error(error.message); process.exitCode = 1; });For a newly authorized deployment, product_variant_deploy(region, productCode, variantCode, payload, {idempotency_key: key, operation_response: true}) opts into the canonical receipt.
PHP
<?php
require __DIR__ . '/vendor/autoload.php';
$client = new \BfApi\BfClient();
$receipt = $client->operation_recover(
getenv('ORIGINAL_REQUEST_KEY'), 'POST', getenv('ORIGINAL_REQUEST_PATH')
);
echo $receipt['operation']['id'] . ' ' . $receipt['operation']['status'] . PHP_EOL;For a newly authorized deployment, product_variant_deploy($region, $productCode, $variantCode, $payload, $key, true) opts into the canonical receipt. PHP recovery uses positional selectors, not the Node.js options object.
Go
package main
import (
"context"
"fmt"
"log"
"os"
bf "blazingfast.io/sdk/go/bfapi"
)
func main() {
client, err := bf.NewClient(bf.Config{})
if err != nil { log.Fatal(err) }
receipt, err := client.OperationRecover(context.Background(),
os.Getenv("ORIGINAL_REQUEST_KEY"), bf.OperationRecoveryOptions{
Method: "POST", Path: os.Getenv("ORIGINAL_REQUEST_PATH"),
})
if err != nil { log.Fatal(err) }
fmt.Println(receipt.Operation.ID, receipt.Operation.Status)
}For a newly authorized deployment, ProductVariantDeploy(region, productCode, variantCode, payload, key, true) opts into the canonical receipt.
SDKs require the explicit deployment key and never automatically retry writes. Cached retries preserve the initial response format, so inspect operation.id or the compatible operation_id. Poll the returned operation link or the SDK operation_get / Go OperationGet helper; only succeeded confirms completion. Receipt results and links identify known resources without exposing credentials.
Optional quote, deployment and recovery
Discover the actual region, product, variant and configuration values first. The following purchase command charges the account; run it only after authorizing the target and final spending ceiling. deployment.json contains the canonical billing_cycle, hostname, os, optional ssh_key_id and max_total fields for the selected VPS, plus any discovered add-ons. Do not mix these with legacy billing/userConfig/maxTotal fields.
bf version
bf capabilities
bf catalog list REGION_CODE vps
bf catalog options REGION_CODE vps VARIANT_CODE
bf billing deploy REGION_CODE vps VARIANT_CODE --file deployment.json --quote
bf billing deploy REGION_CODE vps VARIANT_CODE --file deployment.json --request-key purchase-example-001 --operation-response --wait
bf operations recover --request-key ORIGINAL_KEY --method POST --path /v1/vps/SERVICE_UUID/reboot --wait
bf operations get OPERATION_ID
bf operations wait OPERATION_ID --wait-timeout 300The --quote invocation is a preview, not a purchase, and is optional. --operation-response requests the canonical receipt; --wait polls without resubmitting. Most supported CLI writes generate, save and print an omitted key before dispatch. Retain it: a new invocation without a key represents a new action. Recovery requires the ORIGINAL_KEY and never generates one. The recovery method and path describe the original write; pass both together when disambiguation is needed. DNSSEC enable/disable still require an explicit --request-key.
A wait timeout does not cancel the operation or establish failure. Recover the original receipt before deciding whether to retry the identical write. A 404 lookup is not proof of no execution; 409 requires more precise selectors; 410 requires reconciling resources and billing. Recovery scope and retention remain endpoint-specific.
Purchase discovery and execution recovery
Hosted MCP uses https://mcp.blazingfast.io/mcp and your OAuth connection policy. Local MCP uses the installed SDK/CLI 0.1.17 and your API credentials. Discover the tools actually exposed by the client; their names differ:
- Optional quote: hosted quote_product_variant; local bf_product_variant_quote.
- Execution receipt: hosted get_operation; local bf_operation_get.
- Original-key recovery: hosted recover_operation; local bf_operation_recover.
For both recovery tools, the argument is idempotency_key, even though hosted write tools use request_key. This example recovers an existing VPS reboot; substitute the exact original key and owned service UUID:
{
"idempotency_key": "ORIGINAL_KEY",
"method": "POST",
"path": "/v1/vps/SERVICE_UUID/reboot"
}Recovery is read-only and does not repeat a mutation. Supply method and path together when needed and credential_id only to select the original credential. Reads require current account access and the matching operation-read scope.
Hosted deploy_product is the preferred canonical atomic-purchase workflow. Discover purchase eligibility and configuration first; never invent product/variant IDs, OS codes, SSH-key IDs or regions. A quote is optional, and max_total is the authorized spending ceiling. Hosted writes use request_key as the server Idempotency-Key and honor Read only, Write with approval or Full access. get_operation_request tracks dashboard approval; get_operation tracks execution. Approval is not completion.
Local bf_product_variant_deploy is available only when selected mutations are enabled with BF_API_MCP_ENABLE_MUTATIONS set to 1. It executes under API-key scopes without hosted dashboard approval. Both interfaces retain separate credential controls; execution receipts never expose passwords or private keys. DNSSEC has local tools and its own state contract, with no hosted DNSSEC tool.
See purchase policies, receipt statuses and recovery limitations.
