---
# === IDENTITY ===
id: business/erp-integration/tray-io-integration/2026
canonical_question: "What are Tray.io capabilities for developer-oriented complex integration orchestration?"
aliases:
  - "What can Tray.ai Universal Automation Cloud do for ERP integration?"
  - "How does Tray.io compare to Workato and MuleSoft for enterprise integration?"
  - "What are Tray.io's API rate limits, connectors, and developer features?"
  - "Is Tray.io suitable for complex multi-system ERP orchestration?"
entity_type: erp_integration
domain: business > erp-integration > tray-io-integration
region: global
jurisdiction: global
temporal_scope: 2025-2026

# === SYSTEM PROFILE ===
systems:
  - name: "Tray.ai Universal Automation Cloud"
    vendor: "Tray.ai (formerly Tray.io)"
    version: "UAC 2025"
    edition: "Pro, Team, Enterprise"
    deployment: cloud
    api_surface: "REST, GraphQL, Webhook, Connector SDK"

# === VERIFICATION ===
last_verified: 2026-03-03
confidence: 0.83
version: 1.0
first_published: 2026-03-03

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: volatile
  last_breaking_change: "2024 — rebrand from Tray.io to Tray.ai, UAC launch with Tray Code/Build/Chat"
  next_review: 2026-08-30
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Data payload between workflow steps limited to 6 MB — must chunk larger payloads"
  - "API rate limit: 30 requests/second (1,800/min) with burst to 50 req/s momentarily"
  - "Call Connector endpoint: max 1,000 concurrent requests (concurrency-limited, not rate-limited)"
  - "Standard connector timeout: 45 seconds (120s for CDK-built connectors)"
  - "Webhook trigger payload limited to 1 MB (10 MB for multipart file uploads)"
  - "No pre-built SAP ERP connector — requires HTTP Client or Connector Builder"
  - "Task credits are consumption-based — each workflow step consumes credits; high-volume workflows can exhaust allocation quickly"
  - "Log retention: 7-30 days depending on plan tier"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs a free or open-source integration tool"
    use_instead: "business/erp-integration/n8n-integration/2026"
  - condition: "User needs deep SAP-native integration with IDoc/BAPI support"
    use_instead: "business/erp-integration/sap-integration-suite/2026"
  - condition: "User needs Salesforce-native API-led connectivity"
    use_instead: "business/erp-integration/mulesoft-integration/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: integration_pattern
    question: "What integration pattern do you need?"
    type: choice
    options:
      - "real-time sync (individual records, <1s latency)"
      - "batch/bulk (scheduled, high volume)"
      - "event-driven (webhook, CDC, platform events)"
      - "file-based (CSV/XML import/export)"
  - key: data_volume
    question: "What's your daily data volume?"
    type: choice
    options:
      - "< 1,000 records/day"
      - "1,000-100,000 records/day"
      - "> 100,000 records/day"
  - key: direction
    question: "What's the data flow direction?"
    type: choice
    options:
      - "inbound (writing to this ERP)"
      - "outbound (reading from this ERP)"
      - "bidirectional sync"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/tray-io-integration/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-03-03)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "business/erp-integration/workato-integration/2026"
      label: "Workato iPaaS capabilities and comparison"
    - id: "business/erp-integration/mulesoft-integration/2026"
      label: "MuleSoft Anypoint Platform capabilities"
  solves:
    - id: "business/erp-integration/salesforce-netsuite-playbook/2026"
      label: "Salesforce-to-NetSuite integration playbook"
  alternative_to:
    - id: "business/erp-integration/celigo-integration/2026"
      label: "Celigo iPaaS for ERP-centric integrations"
    - id: "business/erp-integration/workato-integration/2026"
      label: "Workato as alternative enterprise iPaaS"
  often_confused_with:
    - id: "business/erp-integration/mulesoft-integration/2026"
      label: "MuleSoft — API-led connectivity vs Tray's workflow-centric model"

# === SOURCES ===
sources:
  - id: src1
    title: "Tray.ai Documentation — Technical Limits, Timeouts and Retries"
    author: Tray.ai
    url: https://docs.tray.ai/platform/troubleshooting/technical-limits-and-retry-info/
    type: official_docs
    published: 2025-01-15
    reliability: authoritative
  - id: src2
    title: "Tray.ai Developer Portal — Rate Limiting"
    author: Tray.ai
    url: https://developer.tray.ai/developer-portal/getting-started/troubleshooting/rate-limiting-tray/
    type: official_docs
    published: 2025-01-15
    reliability: authoritative
  - id: src3
    title: "Tray.ai Universal Automation Cloud Overview"
    author: Tray.ai
    url: https://tray.ai/universal-automation-cloud
    type: official_docs
    published: 2024-09-01
    reliability: authoritative
  - id: src4
    title: "Tray.io Launches Merlin AI to Automate Complex Workflows"
    author: VentureBeat
    url: https://venturebeat.com/ai/tray-io-launches-merlin-ai-to-automate-complex-workflows-without-llm-training
    type: technical_blog
    published: 2023-05-09
    reliability: high
  - id: src5
    title: "Tray.ai Connector Hub"
    author: Tray.ai
    url: https://tray.io/connectors
    type: official_docs
    published: 2025-01-01
    reliability: authoritative
  - id: src6
    title: "Tray.ai Security Statement"
    author: Tray.ai
    url: https://tray.ai/documentation/tray-uac/governance/security-and-compliance/security-statement/
    type: official_docs
    published: 2025-01-01
    reliability: authoritative
  - id: src7
    title: "Tray.ai Pricing — Compare Plans"
    author: Tray.ai
    url: https://tray.ai/pricing
    type: official_docs
    published: 2025-01-01
    reliability: high
---

# Tray.ai (Tray.io) Integration Capabilities for Complex ERP Orchestration

## TL;DR

- **Bottom line**: Tray.ai is a developer-oriented iPaaS with three build experiences (Tray Code, Tray Build, Tray Chat) and 700+ connectors, best suited for complex multi-system ERP orchestration where workflow logic goes beyond simple point-to-point mapping.
- **Key limit**: 6 MB data payload limit between workflow steps; 30 req/s API rate limit (1,800/min) with burst to 50 req/s; 1,000 max concurrent Call Connector requests. [src1, src2]
- **Watch out for**: No pre-built SAP ERP connector — you must use HTTP Client or build a custom connector via the CDK; task credit consumption scales with step count, not workflow count. [src5]
- **Best for**: Complex orchestration across 3+ systems with branching logic, conditional routing, data transformation, and error handling that exceeds what recipe-based tools can express.
- **Authentication**: OAuth 2.0 (Authorization Code + Client Credentials), API Key, Basic Auth, Custom Service Auth — centralized credential store with auto-refresh. [src6]

## System Profile

Tray.ai (rebranded from Tray.io in 2024) is a cloud-native iPaaS built on the Universal Automation Cloud (UAC) architecture. It targets technical teams that need full control over integration logic while also enabling business technologists through low-code and AI-assisted build experiences. Unlike MuleSoft's API-led connectivity model or Workato's recipe-centric approach, Tray takes a workflow-first approach with deep support for branching, looping, conditional logic, and parallel execution.

The platform operates across three tiers: Pro (entry-level), Team (mid-market), and Enterprise (full governance). All tiers share the same runtime engine but differ in task credits, workspace count, log retention, and governance controls. Tray does NOT offer an on-premise deployment option — it is cloud-only, hosted on AWS.

| Property | Value |
|---|---|
| **Vendor** | Tray.ai (formerly Tray.io) |
| **System** | Universal Automation Cloud (UAC) 2025 |
| **API Surface** | REST, GraphQL (Embedded API), Webhook triggers, Connector SDK (TypeScript) |
| **Current Platform Version** | UAC 2025 (continuous release) |
| **Editions Covered** | Pro, Team, Enterprise |
| **Deployment** | Cloud (AWS-hosted, multi-tenant) |
| **API Docs URL** | [Tray.ai Documentation](https://docs.tray.ai/) |
| **Status** | GA |

## API Surfaces & Capabilities

Tray.ai exposes multiple API surfaces for building integrations, managing workflows programmatically, and embedding integration capabilities into external products. [src2, src3]

| API Surface | Protocol | Best For | Key Capability | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| Workflow REST Triggers | HTTPS/JSON Webhook | Inbound event-driven integrations | Trigger workflows from external systems | 429 at high volume | Yes | No |
| Tray Code APIs (Connectivity, Trigger, Auth) | HTTPS/JSON | Programmatic connector access | Single interface to 700+ apps | 30 req/s | Yes | No |
| GraphQL Embedded API | HTTPS/GraphQL | White-label integration UX | Manage workflows, auth, users programmatically | 30 req/s | Yes | No |
| Call Connector API | HTTPS/JSON | Direct connector operation calls | Execute connector ops from external code | 1,000 concurrent | Yes | No |
| HTTP Client (Universal) | HTTPS/JSON/XML | Any REST/SOAP API without native connector | 15-min timeout, custom auth | Per-target limits | Yes | Yes |
| Connector Builder (CDK) | TypeScript SDK | Custom connectors for unsupported systems | Import OpenAPI specs or build from scratch | N/A (build-time) | N/A | N/A |
| CSV/File Connectors | HTTPS/CSV/XML | Bulk file-based data movement | Up to 1 GB CSV processing | 60-min timeout | No | Yes |

## Rate Limits & Quotas

### Per-Request Limits

| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Data between workflow steps | 6 MB | All connectors | Chunk larger payloads using Data Storage or file connectors |
| Webhook trigger payload | 1 MB | Inbound webhooks | 10 MB for multipart file uploads |
| Trigger event reply body | 1 MB | Synchronous webhook responses | Response to calling system |
| Webhook response size | 2 MB | Outbound responses | Applies to "await workflow and respond" mode |
| CSV row size | 8 KB | CSV Editor | Per-row limit within CSV processing |
| CSV max columns | 4,096 | CSV Editor | Per-file column limit |
| Data Storage single key | 400 KB | Key-value data storage | 32 levels max nesting depth |

[src1]

### Rolling / Daily Limits

| Limit Type | Value | Window | Edition Differences |
|---|---|---|---|
| API rate limit | 30 req/s (1,800/min) | Per second, rolling | All editions; burst to 50 req/s momentarily |
| Call Connector concurrency | 1,000 concurrent requests | Concurrent | Concurrency-limited, not rate-limited |
| Task credits (Pro) | 250,000 starter credits | Monthly | Overage charged per credit |
| Task credits (Team) | 500,000 starter credits | Monthly | Overage charged per credit |
| Task credits (Enterprise) | 750,000 starter credits | Monthly | Custom negotiation available |
| Workspaces (Pro) | 3 | Per account | — |
| Workspaces (Team) | 20 | Per account | — |
| Workspaces (Enterprise) | Unlimited | Per account | — |

[src1, src2, src7]

### Timeout Limits

| Component | Timeout | Notes |
|---|---|---|
| Standard connectors | 45 seconds | 120 seconds for CDK-built connectors |
| HTTP Client (universal) | 15 minutes | Response wait time for custom API calls |
| CSV/Redshift connectors | 60 minutes | Exception for bulk data operations |
| Webhook trigger (sync) | 5 minutes | When using trigger event reply |
| Callable workflow response | No timeout | Can run indefinitely |
| Authentication refresh | Immediate 1st retry | 2nd-3rd retries wait ~20 seconds |

[src1]

## Authentication

Tray.ai provides a centralized authentication store that manages credentials for all connected services. Workflows reference stored auth objects rather than embedding credentials directly. [src6]

| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| OAuth 2.0 Authorization Code | User-context operations, most SaaS apps | Per-service default | Yes (automatic) | Default and preferred flow; supports PKCE |
| OAuth 2.0 Client Credentials | Server-to-server, machine-to-machine | Per-service default | Yes (automatic) | For APIs that don't need user context |
| API Key | Simple service auth (Stripe, SendGrid, etc.) | Until revoked | N/A | Stored encrypted in Tray vault |
| Basic Auth | Legacy systems, on-premise APIs | Per-session | N/A | Username/password stored encrypted |
| Custom Service Auth | Non-standard auth flows | Variable | Configurable | Build custom auth via Connector Builder |

### Authentication Gotchas

- OAuth tokens are stored per-workspace — moving a workflow between workspaces requires re-authentication of all connected services. [src1]
- Tray automatically refreshes tokens on 401/403 responses with 3 retries (1st immediate, 2nd-3rd with ~20s delay) — if all fail, the workflow step errors. [src1]
- For embedded (white-label) deployments, OAuth redirect URLs use the format `<org_name>.integration-authentication.com/oauth2/token` — you must register this URL with each OAuth provider. [src3]
- Connector-level auth is separate from Tray platform API auth — the platform APIs use user tokens obtained via GraphQL mutations. [src2]

## Constraints
<!-- Agents: read this section before recommending any integration approach from this unit.
     These are hard constraints that must not be violated. -->

- **6 MB step payload limit**: Data passed between workflow steps cannot exceed 6 MB. For large datasets, use CSV connectors (up to 1 GB), Data Storage, or file-based intermediaries. This is the #1 constraint developers hit on data-intensive ERP integrations. [src1]
- **No native SAP connector**: SAP ERP, S/4HANA, and SAP BTP do not have pre-built connectors. You must use the HTTP Client connector with custom authentication or build a connector via the CDK. [src5]
- **Task credits are per-step, not per-workflow**: Each connector operation, data transformation, boolean, and loop iteration consumes a task credit. A 20-step workflow processing 1,000 records via a loop consumes 20,000+ credits per execution. [src7]
- **Cloud-only deployment**: No on-premise or hybrid option. All data transits through Tray's AWS infrastructure. Organizations with strict data residency requirements must verify Tray's data processing regions. [src6]
- **Webhook rate limiting**: Webhook triggers using "Validate and respond" or "Await workflow and respond" mode are rate-limited at high volume (hundreds/second triggers HTTP 429). Only "Auto respond with status 200" mode is unthrottled. [src1]
- **Log retention is plan-dependent**: Pro gets 7 days, Enterprise up to 30 days. There is no long-term log archival built in — you must export logs to external systems for compliance. [src7]
- **Generated file TTL**: Files created during workflow execution (CSVs, exports) are automatically deleted after 6 hours. Download URLs also expire at 6 hours. [src1]

## Integration Pattern Decision Tree

```
START — User needs to integrate ERP systems using Tray.ai
|-- What's the integration pattern?
|   |-- Real-time (individual records, <1s latency)
|   |   |-- Target system has native Tray connector?
|   |   |   |-- YES --> Use native connector in workflow with webhook trigger
|   |   |   |-- NO --> Use HTTP Client connector with custom auth
|   |   |-- Data payload < 6 MB per step?
|   |   |   |-- YES --> Direct step-to-step data passing
|   |   |   |-- NO --> Use Data Storage or file intermediary
|   |   |-- Need synchronous response?
|   |       |-- YES --> Webhook trigger with "Await workflow and respond" (5-min timeout)
|   |       |-- NO --> Webhook trigger with "Auto respond 200" + async processing
|   |-- Batch/Bulk (scheduled, high volume)
|   |   |-- Data volume < 1,000 records?
|   |   |   |-- YES --> Loop connector with native connector steps
|   |   |   |-- NO --> CSV connector (up to 1 GB) + callable workflow for parallel processing
|   |   |-- Need to stay within task credit budget?
|   |       |-- YES --> Minimize loop iterations; use bulk API calls where available
|   |       |-- NO --> Standard loop + individual record operations
|   |-- Event-driven (webhook, CDC)
|   |   |-- Source system can push webhooks?
|   |   |   |-- YES --> Webhook trigger on Tray workflow
|   |   |   |-- NO --> Scheduled polling workflow (Scheduler trigger)
|   |   |-- Need guaranteed delivery?
|   |       |-- YES --> Add Data Storage queue + dead letter workflow
|   |       |-- NO --> Direct webhook trigger processing
|   |-- File-based (CSV/XML import/export)
|       |-- File size < 1 GB?
|       |   |-- YES --> CSV/File connector with 60-min timeout
|       |   |-- NO --> Split files externally before ingestion
|       |-- Need transformation?
|           |-- YES --> CSV Editor step (8 KB/row, 4,096 col max)
|           |-- NO --> Direct file pass-through
|-- Which direction?
|   |-- Inbound (writing to ERP) --> Check target system rate limits + Tray 30 req/s limit
|   |-- Outbound (reading from ERP) --> Check source system pagination + 6 MB step limit
|   |-- Bidirectional --> Design conflict resolution in Tray workflow logic FIRST
|-- Error tolerance?
    |-- Zero-loss required --> Data Storage queue + callable workflow retry + error workflow
    |-- Best-effort --> Standard retry policy (3 retries, 40s interval)
```

## Quick Reference

### Platform Capability Comparison

| Capability | Tray.ai | Workato | MuleSoft | Celigo |
|---|---|---|---|---|
| **Approach** | Workflow-first, visual + code | Recipe-based, low-code | API-led connectivity | ERP-centric templates |
| **Connectors** | 700+ | 1,000+ | 400+ (Anypoint Exchange) | 200+ (ERP-focused) |
| **AI Assistant** | Merlin AI (NLP to workflow) | Workato Copilot | Einstein AI | Auto-mapping |
| **Code Access** | Tray Code (3 APIs), JS in steps | Limited custom code | Full Java/Mule DSL | JavaScript transforms |
| **ERP Depth** | Medium — strong NetSuite, weak SAP | Strong — broad ERP coverage | Deep — Salesforce-native | Deep — NetSuite/Salesforce-native |
| **Pricing Model** | Task credits (per step) | Recipes + connections | vCores + API calls | Flows + connections |
| **Starting Price** | ~$600/mo (Pro) | ~$10K/year | ~$15K/year | ~$500/mo |
| **Deployment** | Cloud-only | Cloud-only | Cloud + on-premise (Runtime) | Cloud-only |
| **Embedded/OEM** | Yes (GraphQL Embedded API) | Yes (Embedded platform) | Limited | No |
| **Security** | SOC 2 Type 2, HIPAA, GDPR | SOC 2 Type 2, HIPAA | SOC 2, ISO 27001 | SOC 2 Type 2 |

## Step-by-Step Integration Guide

### 1. Create a Tray.ai Workflow with Webhook Trigger

Set up the workflow entry point that will receive events from an ERP system. [src3]

```javascript
// In Tray Build: Create new workflow
// 1. Click "Create Workflow"
// 2. Select "Webhook" trigger
// 3. Choose "Auto respond with status 200" for high-volume
//    or "Await workflow and respond" for sync responses
// 4. Copy the generated webhook URL

// External system sends to Tray webhook:
const webhookUrl = "https://YOUR_TRAY_WEBHOOK_URL";

const response = await fetch(webhookUrl, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    event: "order_created",
    order_id: "ORD-12345",
    customer: { name: "Acme Corp", erp_id: "CUST-001" },
    line_items: [
      { sku: "WIDGET-A", qty: 100, unit_price: 25.00 }
    ]
  })
});
```

**Verify**: Check Tray workflow logs for the incoming event --> expected: `trigger received` with payload visible in step output.

### 2. Add Connector Steps for ERP Read/Write Operations

Configure the target ERP connector (e.g., NetSuite, Salesforce) to process the incoming data. [src5]

```javascript
// In Tray Build: Add connector step after trigger
// 1. Search connector library for target system (e.g., "NetSuite")
// 2. Select operation (e.g., "Create Record" or "Search Records")
// 3. Map input fields from trigger payload using JSONPath:
//    $.steps.trigger.body.customer.erp_id --> NetSuite Customer Internal ID
//    $.steps.trigger.body.line_items --> Loop connector input

// For systems without native connector (e.g., SAP):
// Use HTTP Client connector:
// - Method: POST
// - URL: https://your-sap-instance.com/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder
// - Headers: { "Authorization": "Bearer {auth.token}", "Content-Type": "application/json" }
// - Body: Map from trigger payload with Data Mapper
```

**Verify**: Step output shows the created/updated record ID from the target ERP system.

### 3. Implement Error Handling with Boolean and Branch Steps

Add conditional logic to handle partial failures and route errors. [src1]

```javascript
// In Tray Build: Add error handling
// 1. After each connector step, add a "Boolean" step
//    Condition: $.steps.previous.error IS NOT NULL
// 2. TRUE branch: Route to error handler
//    - Log error to Data Storage (for dead letter queue)
//    - Send alert via Slack/email connector
// 3. FALSE branch: Continue to next step

// For retry logic:
// - Use "Callable Workflow" trigger for the retry workflow
// - Store failed records in Data Storage with key = record_id
// - Scheduled workflow polls Data Storage every 15 min for retries
// - Max 3 retries before routing to manual review queue
```

**Verify**: Trigger a test failure (invalid record ID) --> expected: error branch executes, record stored in Data Storage.

### 4. Handle High-Volume Data with Loop and Chunking

Process bulk records while staying within Tray platform limits. [src1]

```javascript
// In Tray Build: Bulk processing pattern
// 1. Use "List Helpers - Chunk" step to split large arrays
//    Input: $.steps.trigger.body.records (e.g., 5,000 items)
//    Chunk size: 200 (to stay well under 6 MB step limit)
//
// 2. Use "Loop" connector over chunks
//    For each chunk:
//      a. Call target ERP connector with batch operation
//      b. Collect results
//      c. Add "Delay" step (1-2 seconds) to avoid target system rate limits
//
// 3. Alternatively: Use "Callable Workflow" for parallel processing
//    Main workflow: chunks data, calls child workflow per chunk
//    Child workflow: processes single chunk, returns results
//    Benefit: parallel execution, independent retry per chunk

// IMPORTANT: Each loop iteration = 1 task credit per step inside the loop
// 5,000 records / 200 per chunk = 25 chunks
// 5 steps per chunk = 125 task credits for the chunking portion
// Plus per-record steps inside each chunk
```

**Verify**: Monitor workflow execution logs --> expected: all chunks processed, total task credits match estimate.

## Code Examples

### Python: Trigger a Tray Workflow via Webhook

```python
# Input:  Webhook URL from Tray workflow, ERP event payload
# Output: HTTP 200 (async) or workflow result (sync)

import requests
import json

TRAY_WEBHOOK_URL = "https://YOUR_TRAY_WEBHOOK_URL"

def trigger_tray_workflow(event_type: str, payload: dict) -> dict:
    """Trigger a Tray.ai workflow via webhook with ERP event data."""
    headers = {
        "Content-Type": "application/json",
        # Optional: Add HMAC signature for webhook verification
        "X-Webhook-Signature": compute_hmac(payload)
    }

    response = requests.post(
        TRAY_WEBHOOK_URL,
        headers=headers,
        json={"event": event_type, "data": payload},
        timeout=30  # 5-min max for sync, but set reasonable client timeout
    )

    if response.status_code == 429:
        # Tray rate limit hit — back off and retry
        import time
        time.sleep(2)
        return trigger_tray_workflow(event_type, payload)

    response.raise_for_status()
    return response.json() if response.text else {"status": "accepted"}


def compute_hmac(payload: dict) -> str:
    """Compute HMAC-SHA256 for webhook verification."""
    import hmac, hashlib
    secret = b"YOUR_WEBHOOK_SECRET"
    msg = json.dumps(payload, sort_keys=True).encode()
    return hmac.new(secret, msg, hashlib.sha256).hexdigest()


# Example: Send order created event
result = trigger_tray_workflow("order_created", {
    "order_id": "ORD-12345",
    "customer_id": "CUST-001",
    "total": 2500.00,
    "currency": "USD"
})
print(f"Workflow triggered: {result}")
```

### JavaScript/Node.js: Use Tray Embedded API (GraphQL)

```javascript
// Input:  Tray user token, workflow ID
// Output: Workflow execution status and instance details

// npm install graphql-request@6.x

import { GraphQLClient, gql } from "graphql-request";

const TRAY_GRAPHQL_ENDPOINT = "https://tray.io/graphql";
const USER_TOKEN = process.env.TRAY_USER_TOKEN;

const client = new GraphQLClient(TRAY_GRAPHQL_ENDPOINT, {
  headers: { Authorization: `Bearer ${USER_TOKEN}` },
});

// List all workflows in the workspace
const LIST_WORKFLOWS = gql`
  query {
    viewer {
      workflows {
        edges {
          node {
            id
            name
            enabled
            triggerUrl
          }
        }
      }
    }
  }
`;

// Enable/disable a workflow
const UPDATE_WORKFLOW = gql`
  mutation ($workflowId: ID!, $enabled: Boolean!) {
    updateWorkflowStatus(
      input: { workflowId: $workflowId, enabled: $enabled }
    ) {
      workflow {
        id
        enabled
      }
    }
  }
`;

async function listWorkflows() {
  const data = await client.request(LIST_WORKFLOWS);
  return data.viewer.workflows.edges.map((e) => e.node);
}

async function toggleWorkflow(workflowId, enabled) {
  return client.request(UPDATE_WORKFLOW, { workflowId, enabled });
}

// Usage
const workflows = await listWorkflows();
console.log(`Found ${workflows.length} workflows`);
```

### cURL: Test Webhook Trigger and Check Execution

```bash
# Input:  Tray webhook URL
# Output: HTTP 200 + workflow trigger confirmation

# 1. Trigger a workflow via webhook
curl -X POST "https://YOUR_TRAY_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "invoice_created",
    "invoice_id": "INV-2026-001",
    "amount": 5000.00,
    "currency": "EUR",
    "customer_id": "CUST-042"
  }'
# Expected: HTTP 200 (auto-respond) or JSON response (await mode)

# 2. List workflows via GraphQL API
curl -X POST "https://tray.io/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_USER_TOKEN" \
  -d '{"query": "{ viewer { workflows { edges { node { id name enabled } } } } }"}'
# Expected: JSON with workflow list

# 3. Check solution instance logs (Embedded API)
curl -X POST "https://tray.io/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_MASTER_TOKEN" \
  -d '{"query": "{ viewer { solutionInstances { edges { node { id name enabled } } } } }"}'
```

## Data Mapping

### ERP Integration Field Mapping Patterns

When connecting ERP systems through Tray.ai, field mapping happens in the Data Mapper step, which supports JSONPath expressions, JavaScript transforms, and lookup tables.

| Source Field | Target Field | Type | Transform | Gotcha |
|---|---|---|---|---|
| Salesforce: Account.Name | NetSuite: customer.companyName | String | Direct mapping | NetSuite max 83 chars vs Salesforce 255 |
| Salesforce: Opportunity.Amount | NetSuite: salesOrder.total | Currency | Currency conversion if multi-currency | Must set exchange rate subsidiary |
| SAP: VBAK-NETWR (net value) | Salesforce: Opportunity.Amount | Decimal | Divide by 100 (SAP stores in smallest unit) | SAP CURR fields store in minor currency units |
| NetSuite: transaction.tranDate | Salesforce: Opportunity.CloseDate | DateTime | Format conversion (ISO 8601 to YYYY-MM-DD) | NetSuite timezone = subsidiary timezone |
| Any: Multi-value field | Tray: JSON array | Array | Split/join with List Helpers | Step payload limit 6 MB for large arrays |

### Data Type Gotchas

- Tray.ai Data Mapper outputs JSON strings by default — numeric ERP fields (amounts, quantities) must be explicitly cast using JavaScript steps or the "Type Converter" helper to avoid string-to-number mismatches downstream. [src1]
- Date/time fields lose timezone information when passing through Tray workflow steps unless explicitly preserved — use ISO 8601 with timezone offset (e.g., `2026-03-03T10:00:00+01:00`) in all transformations. [src1]
- NetSuite multi-select custom fields serialize as pipe-delimited (`val1|val2`) in SuiteTalk but Tray's NetSuite connector returns them as arrays — branching on string vs array type is needed when the connector version changes. [src5]
- Null vs empty string handling differs between Tray connectors — Salesforce connector returns `null`, NetSuite connector returns `""` for empty fields. Use Boolean step to normalize before comparison logic. [src5]

## Error Handling & Failure Points

### Common Error Codes

| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| HTTP 429 | Rate limit exceeded | >30 req/s to Tray API or high-volume webhooks | Exponential backoff: wait 2^n seconds; use "Auto respond 200" for webhooks |
| STEP_TIMEOUT | Connector operation timed out | Standard connector exceeded 45s timeout | Switch to HTTP Client (15-min timeout) or break into smaller operations |
| PAYLOAD_TOO_LARGE | Step data exceeds 6 MB | Large dataset between workflow steps | Use CSV connector, Data Storage, or chunk into smaller payloads |
| AUTH_REFRESH_FAILED | OAuth token refresh failed after 3 retries | Expired refresh token or revoked access | Re-authenticate the connector in Tray UI; check token lifetime on provider side |
| CONNECTOR_ERROR | Target system returned error | Invalid data, missing required fields, permission denied | Check step input mapping; verify connector auth permissions |
| WORKFLOW_DISABLED | Workflow triggered but not enabled | Workflow was disabled manually or via API | Enable workflow in Tray UI or via GraphQL mutation |

[src1, src2]

### Failure Points in Production

- **Task credit exhaustion mid-workflow**: Workflows stop executing when account task credits are depleted. There is no graceful mid-run handling — steps simply fail. Fix: `Set up credit usage alerts at 80% threshold; implement credit monitoring via Tray's usage API; design workflows to minimize step count per record`. [src7]
- **6 MB step payload overflow on growing datasets**: Works in dev with 100 records, fails in production with 10,000. The error message is not always obvious. Fix: `Use CSV connector for datasets >1,000 records; implement Data Storage for intermediate results; chunk payloads with List Helpers before processing`. [src1]
- **OAuth token expiration during long-running bulk workflows**: A 60-minute CSV processing job can outlast the access token. Tray auto-refreshes on 401 but only retries 3 times. Fix: `Pre-refresh tokens at workflow start; use service account auth (Client Credentials) instead of user-context auth for batch workflows`. [src1]
- **Webhook replay on Tray platform restarts**: During rare platform maintenance windows, webhooks can be replayed. Without idempotency in target ERP, this creates duplicate records. Fix: `Implement idempotency keys in workflow logic; use Data Storage to track processed event IDs; add deduplication step before ERP write operations`. [src1]
- **Connector version updates break field mappings**: When Tray updates a connector version, field names or response structures can change. Fix: `Pin connector versions in production workflows; test in a separate workspace before promoting; implement field-existence checks with Boolean steps`. [src5]

## Anti-Patterns

### Wrong: Processing large datasets record-by-record in a single loop

```javascript
// BAD — each record = N steps = N task credits; 10K records * 5 steps = 50K credits
// Also: 6 MB step limit will be hit as loop accumulates results
// Loop Connector:
//   For each record in $.steps.trigger.body.records (10,000 items):
//     Step 1: Look up customer in NetSuite
//     Step 2: Transform data
//     Step 3: Create/Update record in NetSuite
//     Step 4: Log result
// Total: 40,000 task credits, likely hits payload limit
```

### Correct: Chunk data and use callable workflows for parallel batch processing

```javascript
// GOOD — chunk into 200-record batches, process in parallel callable workflows
// Main Workflow:
//   Step 1: List Helpers - Chunk (size: 200) --> 50 chunks
//   Step 2: Loop over chunks
//     Step 2a: Call "Batch Processor" workflow with chunk as input
//
// "Batch Processor" Callable Workflow:
//   Step 1: NetSuite - Bulk Create/Update (batch operation, single API call)
//   Step 2: Return results
//
// Total: ~150 task credits (main) + 50 * 2 steps (child) = 250 credits
// 160x more efficient than record-by-record
```

### Wrong: Using synchronous webhook mode for high-volume event streams

```javascript
// BAD — "Await workflow and respond" mode rate-limits at high volume
// and has 5-minute timeout; hundreds of events/second triggers 429s
// Webhook trigger: "Await workflow and respond"
// + Complex 20-step workflow processing each event synchronously
// Result: 429 errors, dropped events, unhappy source systems
```

### Correct: Async webhook with queue pattern for reliable high-volume processing

```javascript
// GOOD — "Auto respond with status 200" (no rate limit) + async processing
// Webhook trigger: "Auto respond with status 200"
//   Step 1: Data Storage - Write event to queue (key: event_id, value: payload)
//   Step 2: Done (source system gets immediate 200)
//
// Separate scheduled workflow (runs every 1 min):
//   Step 1: Data Storage - Read all queued events
//   Step 2: Process batch
//   Step 3: Data Storage - Delete processed events
//   Step 4: Error handler for failed events (move to DLQ)
```

### Wrong: Hardcoding field mappings without null/type checks

```javascript
// BAD — assumes all fields exist and have expected types
// Data Mapper:
//   target.amount = $.steps.salesforce.Amount
//   target.name = $.steps.salesforce.Account.Name
//   target.date = $.steps.salesforce.CloseDate
// Fails when: Amount is null, Account is a deleted reference, CloseDate format changes
```

### Correct: Defensive mapping with Boolean checks and type conversion

```javascript
// GOOD — null checks + type conversion + fallback values
// Step 1: Boolean - Check if $.steps.salesforce.Amount is not null
//   TRUE:  Type Converter - Convert Amount to Number
//   FALSE: Set default value (0.00)
// Step 2: Boolean - Check if $.steps.salesforce.Account is not null
//   TRUE:  Map Account.Name
//   FALSE: Set to "Unknown Customer" + flag for review
// Step 3: Script step (JavaScript):
//   const closeDate = steps.salesforce.CloseDate;
//   return closeDate ? new Date(closeDate).toISOString() : new Date().toISOString();
```

## Common Pitfalls

- **Task credit math blindsides budget**: Developers build workflows in dev with 10 test records and deploy to production processing 100K records. Each step in a loop multiplies credits. A seemingly simple 5-step workflow processing 50K records/day = 250K credits/day = entire Pro tier allocation in 1 day. Fix: `Calculate task credits BEFORE deploying: (steps_per_record * daily_volume * runs_per_day). Use bulk connector operations to reduce step count per record`. [src7]
- **Connector timeouts on slow ERP APIs**: SAP and Oracle ERP Cloud APIs often respond in 10-30 seconds for complex queries. The default 45-second connector timeout leaves no margin. Fix: `Use the HTTP Client connector (15-min timeout) instead of native connectors for slow endpoints; implement async polling patterns for long-running ERP operations`. [src1]
- **Data Storage scope confusion**: "Current Run" scope data persists for 30 days, not just the current execution. Developers assume it's cleared between runs and get stale data. Fix: `Explicitly delete Data Storage keys at workflow end; use unique run-scoped keys (e.g., prefix with execution_id)`. [src1]
- **Workspace isolation breaks cross-team workflows**: Auth credentials are workspace-scoped. A workflow moved to a different workspace loses all connector authentications. Fix: `Plan workspace architecture before building; use Tray's solution packaging for cross-workspace deployment; re-authenticate all connectors after workspace moves`. [src6]
- **CSV connector silently truncates at 8 KB per row**: Wide ERP records (SAP material masters with 200+ fields) can exceed the per-row limit. No error is thrown — data is silently truncated. Fix: `Split wide records into multiple CSVs by field group; verify output row lengths in testing; use JSON-based Data Storage instead of CSV for wide records`. [src1]
- **Merlin AI generates workflows that don't handle errors**: AI-generated workflows from natural language prompts typically lack error handling, retry logic, and edge case handling. Fix: `Always review and augment Merlin-generated workflows; add error handling branches manually; test with invalid data before deploying`. [src4]

## Diagnostic Commands

```bash
# Check Tray API rate limit status (look for 429 responses)
curl -X POST "https://tray.io/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TRAY_USER_TOKEN" \
  -d '{"query": "{ viewer { name } }"}' \
  -w "\nHTTP Status: %{http_code}\n"
# Expected: HTTP 200 with viewer name; 429 = rate limited

# List all workflows and their status
curl -X POST "https://tray.io/graphql" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TRAY_USER_TOKEN" \
  -d '{"query": "{ viewer { workflows { edges { node { id name enabled triggerUrl } } } } }"}'

# Test a webhook trigger endpoint
curl -X POST "$TRAY_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -d '{"test": true, "timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}'
# Expected: HTTP 200 (async) or JSON response (sync)

# Check connector authentication status (via workflow test run)
# In Tray UI: Open workflow --> click connector step --> "Test" button
# Or via GraphQL: query workflow instance logs for AUTH_REFRESH_FAILED errors

# Monitor task credit usage
# In Tray UI: Settings --> Usage --> Task Credits
# No API endpoint for credit balance (UI-only as of 2026)
```

## Version History & Compatibility

| Platform Version | Release Date | Status | Breaking Changes | Migration Notes |
|---|---|---|---|---|
| UAC 2025 (Tray Code/Build/Chat) | 2024-09 | Current | Rebrand from Tray.io to Tray.ai; 3 new APIs (Connectivity, Trigger, Auth) | Existing workflows unaffected; new APIs are additive |
| Merlin AI Integration | 2023-05 | Current | None | NLP workflow generation added; optional feature |
| Enterprise Core Refresh | 2023-01 | Current | SSO configuration changes | Requires re-setup of SSO for existing Enterprise customers |
| Embedded Platform v2 | 2022-06 | Supported | GraphQL schema changes for solution instances | Update GraphQL queries; old mutations deprecated |
| Classic Platform | Pre-2022 | Deprecated | — | Migrate to UAC; classic workflows remain functional but no new features |

[src3, src4]

### Deprecation Policy

Tray.ai follows a continuous release model with no numbered API versions. Platform changes are deployed continuously, with breaking changes communicated via in-app notifications and release notes. Connector updates are generally backward-compatible, but major connector version bumps (e.g., NetSuite connector v2 to v3) may change response schemas. Tray maintains backward compatibility for at least 12 months on major connector versions. [src3]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Complex multi-system orchestration with branching, loops, and conditional logic | Simple point-to-point data sync between 2 systems | Celigo (simpler ERP-focused templates) or Zapier (basic automation) |
| Need embedded/white-label integration UX for your SaaS product | Need deep SAP-native integration with IDoc/BAPI/RFC support | SAP Integration Suite or MuleSoft with SAP connector |
| Development team comfortable with JavaScript and API concepts | Team needs purely no-code drag-and-drop with minimal training | Workato (more guided recipe-based experience) |
| Need AI-assisted workflow generation (Merlin AI) for rapid prototyping | Need full API lifecycle management (design, mock, test, deploy, version) | MuleSoft Anypoint Platform |
| Budget is $500-$5K/month and need enterprise-grade security | Budget is <$500/month or need free tier | n8n (self-hosted open source) or Make.com |
| High-volume webhook-driven event processing (with async pattern) | Need sub-100ms latency for real-time API proxying | MuleSoft (API gateway) or Kong/AWS API Gateway |

## Cross-System Comparison

| Capability | Tray.ai | Workato | MuleSoft | Celigo |
|---|---|---|---|---|
| **Architecture** | Workflow-first, visual + code | Recipe-based, low-code | API-led connectivity | ERP template-first |
| **Connectors** | 700+ | 1,000+ | 400+ (Exchange) | 200+ (ERP-focused) |
| **AI Copilot** | Merlin AI (NLP to full workflow) | Workato Copilot | Einstein AI | Auto-mapping |
| **Developer API** | GraphQL + 3 REST APIs | REST Admin API | Anypoint CLI + REST API | REST Admin API |
| **Connector SDK** | CDK (TypeScript) | SDK (Ruby) | Custom Connector SDK (Java) | JavaScript transforms |
| **SAP Support** | No native connector (HTTP only) | Native SAP connector | Deep SAP connector | Native SAP connector |
| **NetSuite Support** | Native connector (strong) | Native connector (strong) | Via connector | Native connector (deep) |
| **Bulk Processing** | CSV connector (1 GB), 60-min timeout | Batch recipes, 200 records/batch | Batch processing, DataWeave | Smart Map bulk sync |
| **Embedded/OEM** | Yes (Embedded API, white-label) | Yes (Embedded platform) | Limited (API Manager) | No |
| **Max Payload/Step** | 6 MB (between steps) | 100 MB (recipe data) | No hard limit (JVM-dependent) | 5 MB (default) |
| **Deployment** | Cloud-only (AWS) | Cloud-only | Cloud + on-premise (Runtime) | Cloud-only |
| **Compliance** | SOC 2 Type 2, HIPAA, GDPR | SOC 2 Type 2, HIPAA | SOC 2, ISO 27001, PCI | SOC 2 Type 2 |

## Important Caveats

- Task credit pricing is opaque — Tray does not publicly disclose per-credit costs or overage rates. Negotiate credit volume and overage pricing upfront during contract discussions. [src7]
- The 6 MB inter-step payload limit is the most commonly hit constraint in ERP integrations and is not obvious during development with small test datasets. Always test with production-scale data volumes. [src1]
- No native SAP connector means SAP integrations require significantly more development effort (HTTP Client configuration, custom auth, response parsing) compared to Workato or MuleSoft alternatives. [src5]
- Tray.ai is cloud-only with no on-premise deployment option. Organizations in regulated industries (banking, healthcare, government) must verify that data transit through Tray's AWS infrastructure meets their compliance requirements. [src6]
- Connector updates are pushed automatically — there is no way to pin a specific connector version. Test critical workflows after any connector update notification. [src5]
- Merlin AI workflow generation is a starting point, not production-ready — always add error handling, logging, and edge case management to AI-generated workflows. [src4]

## Related Units

- [Workato iPaaS Integration Capabilities](/business/erp-integration/workato-integration/2026)
- [MuleSoft Anypoint Platform Capabilities](/business/erp-integration/mulesoft-integration/2026)
- [Celigo iPaaS for ERP-Centric Integrations](/business/erp-integration/celigo-integration/2026)
- [Salesforce-to-NetSuite Integration Playbook](/business/erp-integration/salesforce-netsuite-playbook/2026)
