> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://onepin.ai/docs/reference/api-reference/templates/estimate-template-api-v-1-templates-template-id-estimate-get/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://onepin.ai/_mcp/server. # Estimate Template GET https://api.onepin.ai/api/v1/templates/{template_id}/estimate Estimate the credit cost of running a workflow built from this template. Returns a per-unit pricing guide expressed in credits per `unit_chars` input characters (default 1,000). Because the template does not contain the caller's actual script, the estimate uses a synthetic fixed-length input to compute a reproducible per-unit rate. Multiply by your expected character count to project total cost. The response distinguishes variable costs (scale with script length, e.g. synthesis) from fixed costs (apply once per run regardless of length). A node-level breakdown is included so callers can see which processing steps drive the cost. Results are cached against the template definition and current pricing rates. `cache_status` indicates whether this response was served from cache (`hit`), computed fresh (`miss`), or recomputed because the definition or rates changed (`stale`). Visibility rules match `GET /templates/{id}` — own-workspace templates use the draft definition; cross-workspace templates use the published snapshot. Dual-auth: Bearer JWT or API key (scope `templates:read`). Reference: https://onepin.ai/docs/reference/api-reference/templates/estimate-template-api-v-1-templates-template-id-estimate-get ## Authentication - `Authorization` header (bearer token, required) — Clerk JWT token - `Authorization` header (bearer token, required) — Onepin live API key (`op_live_...`). Test and public keys are reserved in Phase 1. ## Servers - `https://api.onepin.ai` (prod, default) - `https://dev-api.onepin.ai` (dev) ## Request ### Path parameters - `template_id` (string, required) — Case-sensitive 8-character base62 template identifier. ### Headers - `X-Workspace-Id` (string, optional, nullable) ## Response ### 200 Successful Response - `data` (TemplateEstimateResponse, required) — Per-unit pricing guide for a visible template snapshot. Templates do not contain the caller's final script. Costs are therefore quoted for a fixed input-character unit plus fixed workflow overhead; cloned workflows still use `EstimateResponse` once real script text exists. - `meta` (Meta, required) ## Errors ### 422 Unprocessable Entity Error Validation Error - `detail` (list of ValidationError, optional) ## Types ### TemplateEstimateResponse Per-unit pricing guide for a visible template snapshot. Templates do not contain the caller's final script. Costs are therefore quoted for a fixed input-character unit plus fixed workflow overhead; cloned workflows still use `EstimateResponse` once real script text exists. - `unit_chars` (integer, required) — Character count of the synthetic input used to compute the per-unit rates. Divide your expected script length by this value and multiply by the per-unit credit fields to project total cost. - `variable_min_credits_per_unit` (integer, required) — Minimum variable credits per `unit_chars` characters (best-case pricing, scales with script length). - `variable_expected_credits_per_unit` (integer, required) — Expected variable credits per `unit_chars` characters (typical pricing). - `variable_max_credits_per_unit` (integer, required) — Maximum variable credits per `unit_chars` characters (worst-case pricing). - `fixed_min_credits` (integer, required) — Minimum fixed credits charged once per run regardless of script length. - `fixed_expected_credits` (integer, required) — Expected fixed credits per run. - `fixed_max_credits` (integer, required) — Maximum fixed credits per run. - `total_min_credits_per_unit` (integer, required) — Total minimum credits per `unit_chars` (variable_min + fixed_min). - `total_expected_credits_per_unit` (integer, required) — Total expected credits per `unit_chars`. - `total_max_credits_per_unit` (integer, required) — Total maximum credits per `unit_chars`. - `breakdown` (list of NodeEstimate, required) — Per-node credit breakdown showing which processing steps drive the cost. - `source_snapshot` (enum, required) — `draft` when the estimate is based on the owner's live definition; `published` when based on the gallery snapshot. - Allowed values: `draft`, `published` - `source_node_ids` (list of string, required) — IDs of the source nodes used to anchor the estimate calculation. - `definition_fingerprint` (string, required) — Hash of the template definition at the time this estimate was computed. Changes when the workflow graph is modified. - `rate_fingerprint` (string, required) — Hash of the pricing rates used. Changes when credit rates are updated. - `cache_status` (enum, required) — `hit` — served from cache; `miss` — computed fresh (no prior cache); `stale` — recomputed because the definition or rates changed. - Allowed values: `hit`, `miss`, `stale` - `computed_at` (datetime, required) — UTC timestamp when this estimate was last computed. ### Meta - `request_id` (string, required) - `timestamp` (datetime, required) ### ValidationError - `loc` (list of ValidationErrorLocItems, required) - `msg` (string, required) - `type` (string, required) - `input` (any, optional) - `ctx` (ValidationErrorCtx, optional) ### NodeEstimate Per-node breakdown row for EstimateResponse. - `node_id` (string, required) - `node_type` (string, required) - `min_credits` (integer, required) - `expected_credits` (integer, required) - `max_credits` (integer, required) ### ValidationErrorLocItems ### ValidationErrorCtx ## Examples **Request** ```json {} ``` **Response** ```json { "data": { "unit_chars": 1000, "variable_min_credits_per_unit": 5, "variable_expected_credits_per_unit": 8, "variable_max_credits_per_unit": 12, "fixed_min_credits": 3, "fixed_expected_credits": 5, "fixed_max_credits": 7, "total_min_credits_per_unit": 8, "total_expected_credits_per_unit": 13, "total_max_credits_per_unit": 19, "breakdown": [ { "node_id": "n1a2b3c4", "node_type": "text_synthesis", "min_credits": 4, "expected_credits": 6, "max_credits": 9 }, { "node_id": "n5d6e7f8", "node_type": "data_fetch", "min_credits": 1, "expected_credits": 2, "max_credits": 3 }, { "node_id": "n9g0h1i2", "node_type": "post_processing", "min_credits": 3, "expected_credits": 5, "max_credits": 7 } ], "source_snapshot": "draft", "source_node_ids": [ "n1a2b3c4", "n5d6e7f8", "n9g0h1i2" ], "definition_fingerprint": "a3f5c9d7e1b2f4a6", "rate_fingerprint": "b7d8e9f0a1c2d3e4", "cache_status": "hit", "computed_at": "2024-01-15T09:30:00Z" }, "meta": { "request_id": "req_20240115_093000_abc123", "timestamp": "2024-01-15T09:30:00Z" } } ``` **SDK Code** ```python import requests url = "https://api.onepin.ai/api/v1/templates/template_id/estimate" payload = {} headers = { "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.get(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.onepin.ai/api/v1/templates/template_id/estimate'; const options = { method: 'GET', headers: {Authorization: 'Bearer ', 'Content-Type': 'application/json'}, body: '{}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.onepin.ai/api/v1/templates/template_id/estimate" payload := strings.NewReader("{}") req, _ := http.NewRequest("GET", url, payload) req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.onepin.ai/api/v1/templates/template_id/estimate") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Get.new(url) request["Authorization"] = 'Bearer ' request["Content-Type"] = 'application/json' request.body = "{}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.get("https://api.onepin.ai/api/v1/templates/template_id/estimate") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{}") .asString(); ``` ```php request('GET', 'https://api.onepin.ai/api/v1/templates/template_id/estimate', [ 'body' => '{}', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.onepin.ai/api/v1/templates/template_id/estimate"); var request = new RestRequest(Method.GET); request.AddHeader("Authorization", "Bearer "); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "Authorization": "Bearer ", "Content-Type": "application/json" ] let parameters = [] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.onepin.ai/api/v1/templates/template_id/estimate")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` > Onepin is a voice workflow platform that orchestrates, validates, and ships production-ready audio across 33 TTS models.