> 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/favorite-template-api-v-1-templates-template-id-favorite-post/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://onepin.ai/_mcp/server. # Favorite Template POST https://api.onepin.ai/api/v1/templates/{template_id}/favorite Add a template to the current user's favorites. Favorites are per-user, not per-workspace — the same favorite list is visible regardless of which workspace the caller is currently acting in. Any template visible to the caller (own workspace, public, or starter) can be favorited. Returns 404 when the template does not exist or is not visible to the caller. Calling this endpoint on an already-favorited template is idempotent (returns 200 with the template). Use `DELETE /templates/{id}/favorite` to remove. Does not require `X-Workspace-Id`. Reference: https://onepin.ai/docs/reference/api-reference/templates/favorite-template-api-v-1-templates-template-id-favorite-post ## Authentication - `Authorization` header (bearer token, required) — Clerk JWT token ## 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. ## Response ### 200 Successful Response - `data` (TemplateOut, required) — Response shape. `workspace_id` is intentionally omitted so the gallery endpoint (which returns rows from any workspace) does not leak tenant ownership IDs across tenants. `created_by` is retained as author provenance for public/starter rows. `definition` is the serialized `WorkflowDefinition` JSONB (same shape as `Workflow.definition`) — a template is a reusable workflow snapshot. - `meta` (Meta, required) ## Errors ### 422 Unprocessable Entity Error Validation Error - `detail` (list of ValidationError, optional) ## Types ### TemplateOut Response shape. `workspace_id` is intentionally omitted so the gallery endpoint (which returns rows from any workspace) does not leak tenant ownership IDs across tenants. `created_by` is retained as author provenance for public/starter rows. `definition` is the serialized `WorkflowDefinition` JSONB (same shape as `Workflow.definition`) — a template is a reusable workflow snapshot. - `id` (string, required) — Case-sensitive 8-character base62 template identifier. - `name` (string, required) — Display name of the template. - `definition` (WorkflowDefinition-Output, required) — Full workflow definition (graph + execution config). Use this directly as the `definition` body when creating a workflow from scratch, or clone via `POST /templates/{id}/clone`. - `is_starter` (boolean, required) — `true` for platform-curated starter templates. Starter templates cannot be updated or deleted. - `is_public` (boolean, required) — `true` when this template has an active published snapshot visible in the gallery. - `uses_count` (integer, required) — Number of times this template has been cloned into a workflow. - `created_at` (datetime, required) - `updated_at` (datetime, required) — Last-modified timestamp. For gallery rows this reflects the most recent publish; for own-workspace rows it reflects the most recent draft save. - `description` (string, optional, nullable) — Optional human-readable description. - `category` (enum, optional, nullable) — Gallery category tag, if set. - Allowed values: `media`, `creative`, `business`, `education`, `wellness` - `is_favorite` (boolean, optional, default: false) — `true` when the authenticated caller has favorited this template. - `created_by` (string, optional, nullable) — User ID of the template author. ### 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) ### WorkflowDefinition-Output - `graph` (GraphDefinition-Output, optional) - `execution` (ExecutionDefinition, optional) ### ValidationErrorLocItems ### ValidationErrorCtx ### GraphDefinition-Output - `nodes` (list of GraphNode, optional) - `edges` (list of GraphEdge, optional) ### ExecutionDefinition - `steps` (list of string, optional) - `params` (map from string to any, optional) ### GraphNode - `id` (string, required) - `type` (enum, required) - Allowed values: `source_script`, `operator_translator`, `operator_normalizer`, `operator_generator`, `operator_phoneme_injector`, `sink_preview`, `validator_error_rate`, `validator_naturalness`, `validator_noise`, `validator_pronunciation`, `operator_pronunciation_corrector` - `position` (NodePosition, required) - `name` (string, optional, nullable) - `config` (map from string to any, optional) - `config_version` (integer, optional, default: 1) ### GraphEdge - `id` (string, required) - `source` (string, required) - `sourcePort` (string, required) - `target` (string, required) - `targetPort` (string, required) ### NodePosition - `x` (double, required) - `y` (double, required) ## Examples **Response** ```json { "data": { "id": "string", "name": "string", "definition": { "graph": { "nodes": [ { "id": "string", "type": "source_script", "position": { "x": 1.1, "y": 1.1 }, "name": "string", "config": {}, "config_version": 1 } ], "edges": [ { "id": "string", "source": "string", "sourcePort": "string", "target": "string", "targetPort": "string" } ] }, "execution": { "steps": [ "string" ], "params": {} } }, "is_starter": true, "is_public": true, "uses_count": 1, "created_at": "2024-01-15T09:30:00Z", "updated_at": "2024-01-15T09:30:00Z", "description": "string", "category": "media", "is_favorite": false, "created_by": "string" }, "meta": { "request_id": "string", "timestamp": "2024-01-15T09:30:00Z" } } ``` **SDK Code** ```python import requests url = "https://api.onepin.ai/api/v1/templates/template_id/favorite" headers = {"Authorization": "Bearer "} response = requests.post(url, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.onepin.ai/api/v1/templates/template_id/favorite'; const options = {method: 'POST', headers: {Authorization: 'Bearer '}}; 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" "net/http" "io" ) func main() { url := "https://api.onepin.ai/api/v1/templates/template_id/favorite" req, _ := http.NewRequest("POST", url, nil) req.Header.Add("Authorization", "Bearer ") 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/favorite") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["Authorization"] = 'Bearer ' response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.onepin.ai/api/v1/templates/template_id/favorite") .header("Authorization", "Bearer ") .asString(); ``` ```php request('POST', 'https://api.onepin.ai/api/v1/templates/template_id/favorite', [ 'headers' => [ 'Authorization' => 'Bearer ', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.onepin.ai/api/v1/templates/template_id/favorite"); var request = new RestRequest(Method.POST); request.AddHeader("Authorization", "Bearer "); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = ["Authorization": "Bearer "] let request = NSMutableURLRequest(url: NSURL(string: "https://api.onepin.ai/api/v1/templates/template_id/favorite")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers 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.