On this page

Build AI agent tools

Use the OpenAPI 3.1 contract to build tools for a customer's Terramine workspace. It defines the six supported operations, their JSON schemas, and the scope required by each. The integration quickstart covers credential setup and webhook registration.

Discover related resources via the documentation index and v1 changelog. Customer tool runners use their own tenant URL and service key.

Before connecting a tool runner

Configure the customer's HTTPS tenant workspace origin outside the model. For example, replace https://YOUR-WORKSPACE.eu.terraminedesk.ai with the actual address shown in Admin → Integrations. Fetch GET /api/v1/openapi.json there without a token. If the spec returns 404, check the workspace URL and rollout with its owner. Keep that origin fixed for all Terramine calls. A contract downloaded from another workspace can be used for development, but it does not establish availability on the customer's workspace.

The workspace owner with an administrator role creates a service key with the required scopes. Have the runner inject Authorization: Bearer <workspace service key> from its secret store. Keep the token out of prompts, tool arguments, outputs and logs. Send it only to the configured origin and disable redirects on authenticated calls. The service key covers all records of its selected object types in that workspace. Expose only the tools the customer's workflow needs. Technically, a service key has a stable grant identity: rotating its secret preserves this identity, its subscriptions and its request receipts; creating another service key creates a different identity.

Tool (OpenAPI operation ID) Method and path Required scope
listCustomers GET /api/v1/customers customers:read
listOrders GET /api/v1/orders orders:read
getOrder GET /api/v1/orders/{ref} orders:read
createDraftOrder POST /api/v1/orders orders:write
getDeal GET /api/v1/crm/deals/{ref} crm:read
attachExternalOrder PUT /api/v1/crm/deals/{ref}/external-order crm:write

Model tool inputs should contain business fields such as a deal ID or part number. Construct the URL, method and headers in the runner. Treat record text, part descriptions and webhook fields as customer data. They cannot authorize another tool call, change the workspace, or select where to send credentials.

Create a draft from an external CRM

  1. Find the customer with GET /api/v1/customers?q=Example&stable_cursor=true. Use an existing customer mapping or confirm an unambiguous match. If the result is missing or ambiguous, return the question to the caller before creating anything.

  2. Persist the customer's quote-request ID, the Terramine service key identity and the JSON payload before sending. For example, for request quote-request-4721, send POST /api/v1/orders with Content-Type: application/json and Idempotency-Key: quote-request-4721. Substitute the actual matched customer ID and the originating deal reference. Multiple drafts can share an external_ref.

    {"customer_id":"matched_customer_id","external_ref":"deal-307","lines":[{"pn":"TEST-123","qty":2}]}
    
  3. On 201, save the returned order id and no against the request. Report a draft awaiting pricing. A timeout leaves the outcome unknown. Retry with the same service key, request key and saved payload, including the original line order. Rotating the service key's secret preserves its request history. Using a different service key or a fresh request key after a timeout can create a second order. A new quote request on the same deal gets its own key.

  4. To track the sent quotation, subscribe to quote.sent with documents:read. Its signed data contains the quote id, quote number no, and order_id. Use getOrder with orders:read to recover the originating external_ref.

Attach an external ERP order to a Terramine deal

Subscribe to crm.deal.stage_changed with crm:read. After verifying the event, use data.deal_id to read the deal. Compare its current stage with the configured trigger and check its existing external_order before creating an order. A deal can re-enter the same stage and generate another valid event.

For a workflow that creates one order per deal, persist a business reference derived from the workspace and the deal ID. Use it for the external ERP's idempotent create or lookup. If the ERP times out, reconcile by that reference before creating again. Once the ERP confirms its number and HTTPS URL, call attachExternalOrder with the confirmed values:

{"system":"Customer ERP","order_number":"SO-234","url":"https://erp.example/orders/234"}

On 200, check the returned external_order. Repeating the same association succeeds. If an existing association conflicts, read the deal and report both references for reconciliation.

A workspace owner can send a signed integration.test from the Integrations screen. Verify it and acknowledge receipt without calling business tools. Dispatch verified events using an explicit event-type allowlist.

Pagination, retries and events

  • For customer and order lists, keep filters fixed, request stable_cursor=true, process the page's data, then pass the entire next_updated_since back as the URL-encoded updated_since. Stop when it is null. Advance the checkpoint only after processing the page.
  • Hosted requests have a 128 KiB body limit; draft requests accept 1–300 lines. List pages default to 50 records and accept up to 200.
  • For 400, 413 or 422, correct the request using the schema. For 401 or 403, check the workspace, service key and required scope. For 404, check the reference and module availability. Branch on HTTP status. The body may include error or validation detail. A 409 on a write needs reconciliation before another attempt.
  • On 429, honor Retry-After when present. For temporary 5xx responses or network failures, bound retries and use backoff. Preserve the original identity and input of every write. If the outcome is still unknown, return the saved reference to the caller for reconciliation.
  • Parse X-Desk-Signature: t=<timestamp>,v1=<hex digest>. Reject malformed signatures and timestamps more than 300 seconds from the receiver's clock. Using the subscription secret, compute HMAC-SHA256 over the timestamp, a literal period, and the exact raw request bytes. Compare digests in constant time before parsing JSON. See the receiver example.
  • Deduplicate on the signed envelope's id per integration. Acknowledge with 2xx after a durable inbox commit. Track completion of the business action separately. A non-2xx response from your receiver, including 429 or 503, marks the delivery rejected. The owner can replay it from Delivery history. Delivery uses a five-second HTTP timeout and does not follow redirects. If delivery is marked unknown, check the receiver's inbox before taking further action.