Custom APIs

Any HTTP endpoint can become a tool. You describe the request Postman-style, declare which variables fill it in, and Platica derives the schema the model sees from that.

The mental model

A custom API has two parts:

  • request — the HTTP call to make. Method, URL, headers, body and auth. Wherever you want a dynamic value, you write {{name}}.
  • variables — who fills each {{name}}. The mode field decides the source:
modeWho provides the valueDoes the model see it?
ai (default)The model writes it when calling the toolYes, it appears in the schema
constantFixed value in constantValueNo
contextTaken from the conversation, per contextFieldNo

The JSON Schema the model receives is derived from the ai variables when you enable the tool. You never write it by hand, which is why each variable's description matters: it is literally what the model reads to decide what to send.

The lifecycle

draft ──enable──> enabled ──pause──> paused ──enable──> enabled

Only in enabled does the tool have an entry in the workspace catalog and become connectable to an agent. In draft and paused the configuration exists but nobody sees it.

The integrationId and the catalog toolId are the same identifier, so once enabled you can use it directly in POST /v1/agents/{agentId}/tools .

List APIs

GET https://api.platica.mx/v1/tools/apis

Response

{
  "count": 1,
  "apis": [
    {
      "id": "RuzoaswTBBrhutHyKYZn",
      "name": "order_lookup",
      "toolName": "api_order_lookup",
      "description": "Look up an order status by its reference number.",
      "status": "enabled",
      "method": "GET",
      "url": "https://api.store.com/orders/{{orderId}}",
      "variableCount": 1,
      "lastTestOutcome": "success",
      "lastTestAt": "2026-07-12T09:15:22.109Z",
      "createdAt": "2026-07-10T15:41:03.902Z",
      "updatedAt": "2026-07-12T09:18:44.117Z"
    }
  ]
}
FieldTypeDescription
namestringThe short name you defined.
toolNamestringFull name the model sees: always api_<name>.
statusstringdraft, enabled or paused.
variableCountnumberTotal variables, including those hidden from the model.
lastTestOutcomestring | nullResult of the last test: success, http-error, network-error, schema-error or mapping-error.

Create API

Creates the tool as a draft. It is not available to any agent until you enable it.

POST https://api.platica.mx/v1/tools/apis

Request Body

{
  "name": "order_lookup",
  "description": "Look up a store order status by its reference number. Use it when the customer asks where their order is.",
  "request": {
    "method": "GET",
    "url": "https://api.store.com/orders/{{orderId}}",
    "headers": [
      { "key": "Accept", "value": "application/json" }
    ],
    "auth": {
      "type": "bearer",
      "token": "sk_live_xxx"
    }
  },
  "variables": [
    {
      "name": "orderId",
      "type": "string",
      "description": "Order reference, as shown in the confirmation email.",
      "required": true
    }
  ],
  "response": {
    "path": "data",
    "exclude": ["internal_notes"]
  }
}
ParameterTypeDescriptionRequired
namestringLowercase, starts with a letter or digit, only letters, digits and _ (≤ 62 characters). The model will see it as api_<name>
descriptionstringBetween 10 and 1024 characters. Explain when the agent should call it
requestobjectThe HTTP call. See below
variablesarrayWhat fills each {{name}}. Maximum 50
passContextbooleanRequired to use variables in context mode
contextobject{ "lastMessagesN": 10 } — how many messages {{ctx.lastMessages}} exposes
mappingobjectbodyStrategy (merge, replace, none) and extraBody with fixed pairs
responseobjectTrims the response before handing it to the model
periodicAuthobjectInjects a token obtained by a cron job
encryptPayloadobjectSigns the outbound body as a JWT
{
  "method": "POST",
  "url": "https://api.store.com/orders",
  "params": [
    { "key": "locale", "value": "en-US" }
  ],
  "headers": [
    { "key": "Content-Type", "value": "application/json" }
  ],
  "body": {
    "mode": "json",
    "raw": "{ \"customer\": \"{{customerId}}\", \"note\": \"{{note}}\" }"
  },
  "auth": { "type": "bearer", "token": "sk_live_xxx" },
  "settings": { "timeoutMs": 30000 }
}
FieldTypeDescription
methodstringGET, POST, PUT, PATCH or DELETE.
urlstringTarget URL. Accepts {{variable}} anywhere.
paramsarrayQuery params as { key, value, enabled? }. Maximum 25.
headersarraySame as params. Maximum 25.
bodyobject{ "mode": "none" }, { "mode": "json", "raw": "..." }, { "mode": "text", "raw": "..." } or { "mode": "form-urlencoded", "pairs": [...] }.
authobject{ "type": "none" }, { "type": "bearer", "token" }, { "type": "basic", "username", "password" } or { "type": "apikey", "key", "value", "in": "header" \| "query" }.
settings.timeoutMsnumberBetween 1000 and 60000. Default 30000.

Any value accepts {{variable}}, not just the URL.

{
  "name": "orderId",
  "type": "string",
  "description": "Order reference, as shown in the confirmation email.",
  "required": true,
  "mode": "ai"
}
FieldTypeDescription
namestringReferenced as {{name}} inside request.
typestringstring, number, integer, boolean, array or object.
descriptionstringWhat the model reads. Mandatory for ai variables at enable time.
requiredbooleanWhether the model must always send it.
modestringai (default), constant or context.
constantValueanyOnly with mode: "constant".
contextFieldstringOnly with mode: "context". See below.
enum, format, pattern, minLength, maxLength, minimum, maximum, items, defaultvariousRefinements copied into the model's JSON Schema.

Values accepted in contextField, available when passContext is true:

contextFieldValue
phoneNumberThe customer's number in the conversation
workspaceIdWorkspace ID
conversationIdConversation ID
agentIdID of the calling agent
agentNameName of the calling agent
channelIdChannel the conversation arrived through
lastMessagesLast N messages, per context.lastMessagesN

Large responses burn model context without adding anything. response lets you keep only what matters:

FieldTypeDescription
pathstringPath to the useful fragment, e.g. data.items.
strictPathbooleanWhen true, fails if path is missing instead of returning everything.
includestring[]Only these fields.
excludestring[]Everything except these.
maxBytesnumberTruncate the response to this size. Default 32000.

Response

{
  "status": "success",
  "message": "API tool created successfully",
  "data": {
    "id": "RuzoaswTBBrhutHyKYZn",
    "name": "order_lookup",
    "toolName": "api_order_lookup",
    "status": "draft"
  }
}

Errors

StatusCause
400The name does not match the format, the description is too short, or the request is invalid
409Another tool in the workspace already uses that name

Get API

GET https://api.platica.mx/v1/tools/apis/{integrationId}

URL parameters

ParameterTypeDescriptionRequired
integrationIdstringCustom API identifier

Response

Returns the definition plus the derived toolName. Write-only values are replaced with "[REDACTED]": authentication, sensitive headers/params, constant variables, and the encryptPayload key.

{
  "id": "RuzoaswTBBrhutHyKYZn",
  "toolName": "api_order_lookup",
  "name": "order_lookup",
  "description": "Look up a store order status by its reference number.",
  "status": "enabled",
  "request": {
    "method": "GET",
    "url": "https://api.store.com/orders/{{orderId}}",
    "headers": [{ "key": "Accept", "value": "application/json" }],
    "auth": { "type": "bearer", "token": "[REDACTED]" }
  },
  "variables": [
    {
      "name": "orderId",
      "type": "string",
      "description": "Order reference, as shown in the confirmation email.",
      "required": true,
      "mode": "ai"
    }
  ],
  "version": 3,
  "enabledFunctionRef": "RuzoaswTBBrhutHyKYZn",
  "secretsRedacted": true,
  "createdAt": "2026-07-10T15:41:03.902Z",
  "updatedAt": "2026-07-12T09:18:44.117Z"
}

version increases with every write and is used for concurrency control on update.

You may send "[REDACTED]" back in a PATCH: Platica keeps the current value. Send a new value to replace a credential, or omit the field to preserve it.

Errors

StatusCause
404The custom API does not exist in the workspace

Update API

Partial update: only the fields you send are modified, the rest are kept.

PATCH https://api.platica.mx/v1/tools/apis/{integrationId}

URL parameters

ParameterTypeDescriptionRequired
integrationIdstringCustom API identifier

Request Body

{
  "description": "Look up the status and estimated delivery date of an order.",
  "expectedVersion": 3
}

Accepts the same fields as create , all optional, plus:

ParameterTypeDescription
expectedVersionnumberIf the stored version does not match, responds 409 instead of overwriting someone else's changes

If the tool is enabled, name, description and variable changes propagate to the catalog immediately. status does not change here — use enable and pause for that.

Response

{
  "status": "success",
  "message": "API tool updated successfully",
  "data": {
    "id": "RuzoaswTBBrhutHyKYZn",
    "version": 4
  }
}

Errors

StatusCause
400A field is invalid, or the body is empty
404The custom API does not exist
409expectedVersion mismatch, or the new name is already taken

Test API

Runs the tool with sample values, whether it is a draft or enabled. Every run is recorded in the integration logs.

POST https://api.platica.mx/v1/tools/apis/{integrationId}/test

URL parameters

ParameterTypeDescriptionRequired
integrationIdstringCustom API identifier

Request Body

{
  "dryRun": false,
  "input": {
    "orderId": "MX-48210"
  },
  "context": {
    "phoneNumber": "+5215512345678"
  }
}
ParameterTypeDescriptionRequiredDefault
dryRunbooleanWith true, assembles the request and returns it without calling the APIfalse
inputobjectValues for the ai variables{}
contextobjectTest values for {{ctx.*}}: phoneNumber, workspaceId, conversationId, agentId, agentName, channelId, messages

Always start with dryRun: true to check how the URL, headers and body look with substitutions applied, before hitting the real API.

Response

{
  "status": "success",
  "message": "Test executed",
  "data": {
    "outcome": "success",
    "httpStatus": 200,
    "durationMs": 412,
    "request": {
      "method": "GET",
      "url": "https://api.store.com/orders/MX-48210"
    },
    "response": {
      "status": "in_transit",
      "eta": "2026-07-16"
    }
  }
}

Errors

StatusCause
404The custom API does not exist

A failure from the remote API is not an error of this endpoint: it responds 200 with the detail in data.outcome and data.httpStatus.

Enable API

Publishes the tool to the workspace catalog.

POST https://api.platica.mx/v1/tools/apis/{integrationId}/enable

URL parameters

ParameterTypeDescriptionRequired
integrationIdstringCustom API identifier

Response

{
  "status": "success",
  "message": "API tool enabled successfully",
  "data": {
    "id": "RuzoaswTBBrhutHyKYZn",
    "toolId": "RuzoaswTBBrhutHyKYZn",
    "status": "enabled"
  }
}

toolId is what you pass to POST /v1/agents/{agentId}/tools to give it to an agent.

Enabling an already-enabled tool re-syncs the catalog, which is handy after editing the schema.

Errors

StatusCause
400A model-facing variable is missing its description, or the definition fails validation
404The custom API does not exist
409Another tool in the workspace already uses that name

Pause API

Withdraws the tool from the catalog. Agents stop seeing it immediately, but the configuration is kept intact.

POST https://api.platica.mx/v1/tools/apis/{integrationId}/pause

URL parameters

ParameterTypeDescriptionRequired
integrationIdstringCustom API identifier

Response

{
  "status": "success",
  "message": "API tool paused successfully",
  "data": {
    "id": "RuzoaswTBBrhutHyKYZn",
    "status": "paused"
  }
}

Errors

StatusCause
404The custom API does not exist

Delete API

DELETE https://api.platica.mx/v1/tools/apis/{integrationId}

URL parameters

ParameterTypeDescriptionRequired
integrationIdstringCustom API identifier

Response

{
  "status": "success",
  "message": "API tool deleted successfully",
  "data": {
    "id": "RuzoaswTBBrhutHyKYZn",
    "removedAgentConnections": 3
  }
}

Removes the configuration, its catalog entry, and every agent connection. This cannot be undone — if you only want to switch it off while preserving assignments, use pause .

Errors

StatusCause
404The custom API does not exist