> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.pinnacle.sh/v-2/api-reference/rcs-agents/test/create-agent/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.pinnacle.sh/_mcp/server. # Create Test Agent POST https://api.pinnacle.sh/rcs/test/agents Content-Type: application/json Create a new RCS test agent for development and testing. ## Overview Test agents let you build and test full RCS functionality — rich cards, carousels, buttons, quick replies, and media messages — without going through the full carrier review process. Messages from test agents can only be sent to [whitelisted phone numbers](/api-reference/rcs-agents/test/whitelist-number). ## Limits * **Maximum 5 test agents per account.** ## Image Requirements | Image | Format | Max Size | | ----- | --------- | -------- | | Logo | JPEG, PNG | 50 KB | | Hero | JPEG, PNG | 200 KB | ## After Creation Once your test agent is created, you'll need to: 1. **Whitelist test phone numbers** using [`POST /rcs/test/agents/{agentId}/whitelist`](/api-reference/rcs-agents/test/whitelist-number). 2. **Accept the tester invite** on each whitelisted device. 3. **Send messages** using [`POST /messages/send/rcs`](/api-reference/messages/send-rcs) with the returned agent ID as the `from` field. > **2-Minute Cooldown** > > After creating a test agent, there is a mandatory 2-minute cooldown before you can whitelist phone numbers. > This is a requirement imposed by Google's RBM platform. Reference: https://docs.pinnacle.sh/api-reference/rcs-agents/test/create-agent ## Authentication - `PINNACLE-API-KEY` header (required) — API Key authentication via header ## Request ### Body (application/json) This endpoint expects a CreateTestAgentRequest. - `displayName` (string, required) — Display name of the agent shown to users in RCS conversations. Must be between 1 and 40 characters. - `description` (string, required) — Short description of what the agent does. Shown to users in the agent's profile. Must be between 1 and 100 characters. - `logoUrl` (string, required) — URL to the agent's logo image. Displayed as the agent's avatar in conversations. **Requirements:** - Format: JPEG or PNG - Max file size: 50 KB - Recommended: Square aspect ratio - `heroUrl` (string, required) — URL to the agent's hero banner image. Displayed at the top of the agent's profile. **Requirements:** - Format: JPEG or PNG - Max file size: 200 KB - Recommended: Landscape aspect ratio - `phoneNumbers` (list of AgentPhoneEntry, required) — Contact phone numbers displayed on the agent's profile. At least 1 and up to 3 entries. - `emails` (list of AgentEmailEntry, required) — Contact email addresses displayed on the agent's profile. At least 1 and up to 3 entries. - `websites` (list of AgentWebsiteEntry, required) — Website links displayed on the agent's profile. At least 1 and up to 3 entries. - `privacyUrl` (string, required) — URL to the agent's privacy policy. - `termsUrl` (string, required) — URL to the agent's terms and conditions. - `color` (string, required) — The agent's brand color as a hex color code. Used for UI accents in the RCS conversation. Must have sufficient contrast with white for accessibility. - `isConversational` (boolean, required) — Whether the agent supports two-way conversations. Set to `true` if the agent will respond to user messages. Set to `false` for send-only agents (e.g., notifications). - `agentUseCase` (enum, optional) — The primary use case for the RCS agent. This helps carriers understand the purpose of the agent during review. - `TRANSACTIONAL` — Order confirmations, shipping updates, appointment reminders, and similar transactional notifications. - `PROMOTIONAL` — Marketing messages, offers, discounts, and promotional content. - `OTP` — One-time passwords and verification codes. - `MULTI_USE` — A combination of transactional, promotional, and/or OTP messaging. - Allowed values: `TRANSACTIONAL`, `PROMOTIONAL`, `OTP`, `MULTI_USE` ## Response ### 200 The test agent was created successfully. Use the returned `id` as the `from` field when sending RCS messages, and when whitelisting phone numbers. - `id` (string, required) — The unique agent ID. Use this ID when sending messages, whitelisting numbers, and performing other agent operations. Always prefixed with `agent_`. - `type` (enum, required) — The type of the agent. Test agents always have type `TEST`. - Allowed values: `TEST` - `serviceId` (string, required) — The RCS service ID assigned to this agent by the carrier network. Used internally for routing messages. You can use this to construct RCS deep links manually. - `details` (RcsAgentDetails, required) — The configuration details of an RCS agent, as returned by the GET endpoint. ## Errors ### 400 Bad Request Error Validation failed. The payload has missing required fields and/or invalid types. See [https://zod.dev/error-formatting](https://zod.dev/error-formatting) for more information. - `description` (string, required) — Human-readable summary of validation failures. - `errors` (ZodErrorErrors, required) — Structured dictionary of issues containing two main sections: - `errors`: Array of global validation errors not tied to specific fields - `properties`: Object mapping field names to their specific validation errors, where each field contains an `errors` array ### 401 Unauthorized Error The request lacks valid authentication credentials or the provided credentials are invalid. Ensure you're including a valid API key in the request headers and that your account has the necessary permissions to access this endpoint. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### 403 Forbidden Error Your subscription does not include access to this feature. This occurs when attempting to use functionality that requires a higher subscription tier. Please upgrade your subscription to access this feature. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ### 500 Internal Server Error An internal error occurred. Common causes: - **Agent limit reached:** You can create a maximum of 5 test agents per account. - **Invalid image:** Logo exceeds 50 KB, hero exceeds 200 KB, or image is not JPEG/PNG. - **Invalid color:** The hex color does not have sufficient contrast with white. - `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code. ## Types ### AgentPhoneEntry A phone number contact entry for the RCS agent's contact information. - `number` (string, required) — Phone number in E.164 format (e.g., `+14155550123`). - `label` (string, required) — Display label for the phone number (e.g., "Support", "Sales"). ### AgentEmailEntry An email contact entry for the RCS agent's contact information. - `address` (string, required) — A valid email address. - `label` (string, required) — Display label for the email (e.g., "Support", "Sales"). ### AgentWebsiteEntry A website contact entry for the RCS agent's contact information. - `url` (string, required) — A valid URL for the website. - `label` (string, required) — Display label for the website (e.g., "Website", "Help Center"). ### RcsAgentDetails The configuration details of an RCS agent, as returned by the GET endpoint. - `name` (string, optional) — Display name of the agent. - `description` (string, optional) — Description of the agent. - `iconUrl` (string, optional, nullable) — URL to the agent's logo image. - `heroUrl` (string, optional, nullable) — URL to the agent's hero banner image. - `color` (string, optional) — The agent's brand color hex code. - `phones` (list of RcsAgentDetailsPhonesItems, optional) — Contact phone numbers for the agent. - `emails` (list of RcsAgentDetailsEmailsItems, optional) — Contact email addresses for the agent. - `websites` (list of RcsAgentDetailsWebsitesItems, optional) — Website links for the agent. - `privacyUrl` (string, optional, nullable) — URL to the agent's privacy policy. - `termsUrl` (string, optional, nullable) — URL to the agent's terms and conditions. - `isConversational` (boolean, optional, nullable) — Whether the agent supports two-way conversations. `true` for agents that respond to user messages, `false` for send-only agents (e.g., notifications). - `agentUseCase` (enum, optional, nullable) — The primary use case for the RCS agent. - `TRANSACTIONAL` — Order confirmations, shipping updates, appointment reminders. - `PROMOTIONAL` — Marketing messages, offers, discounts. - `OTP` — One-time passwords and verification codes. - `MULTI_USE` — A combination of transactional, promotional, and/or OTP messaging. - Allowed values: `TRANSACTIONAL`, `PROMOTIONAL`, `OTP`, `MULTI_USE` ### ZodErrorErrors Structured dictionary of issues containing two main sections: - `errors`: Array of global validation errors not tied to specific fields - `properties`: Object mapping field names to their specific validation errors, where each field contains an `errors` array ### RcsAgentDetailsPhonesItems - `phone` (string, optional) — Phone number in E.164 format. - `label` (string, optional) — Display label for the phone number. ### RcsAgentDetailsEmailsItems - `email` (string, optional) — Email address. - `label` (string, optional) — Display label for the email. ### RcsAgentDetailsWebsitesItems - `url` (string, optional) — Website URL. - `label` (string, optional) — Display label for the website. ## Examples ### Created Test Agent **Response** ```json { "id": "agent_abc123def456", "type": "TEST", "serviceId": "acme-support_agent", "details": { "name": "Acme Support", "description": "Get help with your Acme orders and account", "iconUrl": "https://example.com/logo.png", "heroUrl": "https://example.com/hero.png", "color": "#FF6B00", "phones": [ { "phone": "+14155550123", "label": "Support" } ], "emails": [ { "email": "support@example.com", "label": "Support" } ], "websites": [ { "url": "https://example.com", "label": "Website" } ], "privacyUrl": "https://example.com/privacy", "termsUrl": "https://example.com/terms", "isConversational": true, "agentUseCase": "MULTI_USE" } } ``` **SDK Code** ```python Created Test Agent import requests url = "https://api.pinnacle.sh/rcs/test/agents" headers = {"PINNACLE-API-KEY": ""} response = requests.post(url, headers=headers) print(response.json()) ``` ```javascript Created Test Agent const url = 'https://api.pinnacle.sh/rcs/test/agents'; const options = {method: 'POST', headers: {'PINNACLE-API-KEY': ''}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go Created Test Agent package main import ( "fmt" "net/http" "io" ) func main() { url := "https://api.pinnacle.sh/rcs/test/agents" req, _ := http.NewRequest("POST", url, nil) req.Header.Add("PINNACLE-API-KEY", "") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby Created Test Agent require 'uri' require 'net/http' url = URI("https://api.pinnacle.sh/rcs/test/agents") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["PINNACLE-API-KEY"] = '' response = http.request(request) puts response.read_body ``` ```java Created Test Agent import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.pinnacle.sh/rcs/test/agents") .header("PINNACLE-API-KEY", "") .asString(); ``` ```php Created Test Agent request('POST', 'https://api.pinnacle.sh/rcs/test/agents', [ 'headers' => [ 'PINNACLE-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp Created Test Agent using RestSharp; var client = new RestClient("https://api.pinnacle.sh/rcs/test/agents"); var request = new RestRequest(Method.POST); request.AddHeader("PINNACLE-API-KEY", ""); IRestResponse response = client.Execute(request); ``` ```swift Created Test Agent import Foundation let headers = ["PINNACLE-API-KEY": ""] let request = NSMutableURLRequest(url: NSURL(string: "https://api.pinnacle.sh/rcs/test/agents")! 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() ``` ### Create Test Agent **Request** ```json { "displayName": "Acme Support", "description": "Get help with your Acme orders and account", "logoUrl": "https://example.com/logo.png", "heroUrl": "https://example.com/hero.png", "phoneNumbers": [ { "number": "+14155550123", "label": "Support" } ], "emails": [ { "address": "support@example.com", "label": "Support" } ], "websites": [ { "url": "https://example.com", "label": "Website" } ], "privacyUrl": "https://example.com/privacy", "termsUrl": "https://example.com/terms", "color": "#FF6B00", "isConversational": true, "agentUseCase": "MULTI_USE" } ``` **Response** ```json { "id": "agent_abc123def456", "type": "TEST", "serviceId": "acme-support_agent", "details": { "name": "Acme Support", "description": "Get help with your Acme orders and account", "iconUrl": "https://example.com/logo.png", "heroUrl": "https://example.com/hero.png", "color": "#FF6B00", "phones": [ { "phone": "+14155550123", "label": "Support" } ], "emails": [ { "email": "support@example.com", "label": "Support" } ], "websites": [ { "url": "https://example.com", "label": "Website" } ], "privacyUrl": "https://example.com/privacy", "termsUrl": "https://example.com/terms", "isConversational": true, "agentUseCase": "MULTI_USE" } } ``` **SDK Code** ```python Create Test Agent import requests url = "https://api.pinnacle.sh/rcs/test/agents" payload = { "displayName": "Acme Support", "description": "Get help with your Acme orders and account", "logoUrl": "https://example.com/logo.png", "heroUrl": "https://example.com/hero.png", "phoneNumbers": [ { "number": "+14155550123", "label": "Support" } ], "emails": [ { "address": "support@example.com", "label": "Support" } ], "websites": [ { "url": "https://example.com", "label": "Website" } ], "privacyUrl": "https://example.com/privacy", "termsUrl": "https://example.com/terms", "color": "#FF6B00", "isConversational": True, "agentUseCase": "MULTI_USE" } headers = { "PINNACLE-API-KEY": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript Create Test Agent const url = 'https://api.pinnacle.sh/rcs/test/agents'; const options = { method: 'POST', headers: {'PINNACLE-API-KEY': '', 'Content-Type': 'application/json'}, body: '{"displayName":"Acme Support","description":"Get help with your Acme orders and account","logoUrl":"https://example.com/logo.png","heroUrl":"https://example.com/hero.png","phoneNumbers":[{"number":"+14155550123","label":"Support"}],"emails":[{"address":"support@example.com","label":"Support"}],"websites":[{"url":"https://example.com","label":"Website"}],"privacyUrl":"https://example.com/privacy","termsUrl":"https://example.com/terms","color":"#FF6B00","isConversational":true,"agentUseCase":"MULTI_USE"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go Create Test Agent package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.pinnacle.sh/rcs/test/agents" payload := strings.NewReader("{\n \"displayName\": \"Acme Support\",\n \"description\": \"Get help with your Acme orders and account\",\n \"logoUrl\": \"https://example.com/logo.png\",\n \"heroUrl\": \"https://example.com/hero.png\",\n \"phoneNumbers\": [\n {\n \"number\": \"+14155550123\",\n \"label\": \"Support\"\n }\n ],\n \"emails\": [\n {\n \"address\": \"support@example.com\",\n \"label\": \"Support\"\n }\n ],\n \"websites\": [\n {\n \"url\": \"https://example.com\",\n \"label\": \"Website\"\n }\n ],\n \"privacyUrl\": \"https://example.com/privacy\",\n \"termsUrl\": \"https://example.com/terms\",\n \"color\": \"#FF6B00\",\n \"isConversational\": true,\n \"agentUseCase\": \"MULTI_USE\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("PINNACLE-API-KEY", "") 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 Create Test Agent require 'uri' require 'net/http' url = URI("https://api.pinnacle.sh/rcs/test/agents") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["PINNACLE-API-KEY"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"displayName\": \"Acme Support\",\n \"description\": \"Get help with your Acme orders and account\",\n \"logoUrl\": \"https://example.com/logo.png\",\n \"heroUrl\": \"https://example.com/hero.png\",\n \"phoneNumbers\": [\n {\n \"number\": \"+14155550123\",\n \"label\": \"Support\"\n }\n ],\n \"emails\": [\n {\n \"address\": \"support@example.com\",\n \"label\": \"Support\"\n }\n ],\n \"websites\": [\n {\n \"url\": \"https://example.com\",\n \"label\": \"Website\"\n }\n ],\n \"privacyUrl\": \"https://example.com/privacy\",\n \"termsUrl\": \"https://example.com/terms\",\n \"color\": \"#FF6B00\",\n \"isConversational\": true,\n \"agentUseCase\": \"MULTI_USE\"\n}" response = http.request(request) puts response.read_body ``` ```java Create Test Agent import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.pinnacle.sh/rcs/test/agents") .header("PINNACLE-API-KEY", "") .header("Content-Type", "application/json") .body("{\n \"displayName\": \"Acme Support\",\n \"description\": \"Get help with your Acme orders and account\",\n \"logoUrl\": \"https://example.com/logo.png\",\n \"heroUrl\": \"https://example.com/hero.png\",\n \"phoneNumbers\": [\n {\n \"number\": \"+14155550123\",\n \"label\": \"Support\"\n }\n ],\n \"emails\": [\n {\n \"address\": \"support@example.com\",\n \"label\": \"Support\"\n }\n ],\n \"websites\": [\n {\n \"url\": \"https://example.com\",\n \"label\": \"Website\"\n }\n ],\n \"privacyUrl\": \"https://example.com/privacy\",\n \"termsUrl\": \"https://example.com/terms\",\n \"color\": \"#FF6B00\",\n \"isConversational\": true,\n \"agentUseCase\": \"MULTI_USE\"\n}") .asString(); ``` ```php Create Test Agent request('POST', 'https://api.pinnacle.sh/rcs/test/agents', [ 'body' => '{ "displayName": "Acme Support", "description": "Get help with your Acme orders and account", "logoUrl": "https://example.com/logo.png", "heroUrl": "https://example.com/hero.png", "phoneNumbers": [ { "number": "+14155550123", "label": "Support" } ], "emails": [ { "address": "support@example.com", "label": "Support" } ], "websites": [ { "url": "https://example.com", "label": "Website" } ], "privacyUrl": "https://example.com/privacy", "termsUrl": "https://example.com/terms", "color": "#FF6B00", "isConversational": true, "agentUseCase": "MULTI_USE" }', 'headers' => [ 'Content-Type' => 'application/json', 'PINNACLE-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp Create Test Agent using RestSharp; var client = new RestClient("https://api.pinnacle.sh/rcs/test/agents"); var request = new RestRequest(Method.POST); request.AddHeader("PINNACLE-API-KEY", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"displayName\": \"Acme Support\",\n \"description\": \"Get help with your Acme orders and account\",\n \"logoUrl\": \"https://example.com/logo.png\",\n \"heroUrl\": \"https://example.com/hero.png\",\n \"phoneNumbers\": [\n {\n \"number\": \"+14155550123\",\n \"label\": \"Support\"\n }\n ],\n \"emails\": [\n {\n \"address\": \"support@example.com\",\n \"label\": \"Support\"\n }\n ],\n \"websites\": [\n {\n \"url\": \"https://example.com\",\n \"label\": \"Website\"\n }\n ],\n \"privacyUrl\": \"https://example.com/privacy\",\n \"termsUrl\": \"https://example.com/terms\",\n \"color\": \"#FF6B00\",\n \"isConversational\": true,\n \"agentUseCase\": \"MULTI_USE\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift Create Test Agent import Foundation let headers = [ "PINNACLE-API-KEY": "", "Content-Type": "application/json" ] let parameters = [ "displayName": "Acme Support", "description": "Get help with your Acme orders and account", "logoUrl": "https://example.com/logo.png", "heroUrl": "https://example.com/hero.png", "phoneNumbers": [ [ "number": "+14155550123", "label": "Support" ] ], "emails": [ [ "address": "support@example.com", "label": "Support" ] ], "websites": [ [ "url": "https://example.com", "label": "Website" ] ], "privacyUrl": "https://example.com/privacy", "termsUrl": "https://example.com/terms", "color": "#FF6B00", "isConversational": true, "agentUseCase": "MULTI_USE" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.pinnacle.sh/rcs/test/agents")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" 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() ``` > One API for RCS, iMessage, MMS, and SMS. Build, test, and scale every channel — send your first message in minutes, not weeks.