TradeOps API Reference
The TradeOps API lets you programmatically build, run, and inspect manufacturing, customs, freight, and statutory workflows. Every action you can take in the Workflow Studio is available through the API.
New here? Start with the Quick Start guide to make your first request in under five minutes.
What you can do
- Workflows — create, update, and delete the four workflow types: manufacturing, customs, freight, and statutory.
- Steps — add, edit, reorder, and remove the individual stages inside a workflow.
- Templates — install pre-built workflow templates from the TradeOps library.
- Documents — retrieve standard trade documents (ISF, CBP 7501, bills of lading, statutory forms) as structured JSON or PDF.
- Webhooks — receive real-time events when workflows change, documents are generated, or deadlines approach.
Requirements
- An active TradeOps workspace with the API Access add-on enabled.
- A secret API key issued from the workspace settings.
- HTTPS-only outbound traffic (TLS 1.2 minimum).
Authentication
Authenticate every request with a Bearer token in the Authorization header. API keys are scoped to a single workspace and inherit that workspace's role-based permissions.
API Keys
Generate API keys from Workspace Settings → API Access → Keys. Each key has a name, an environment (live or test), a scope list, and an optional expiry date.
# Live key curl https://api.tradeops.io/v1/workflows \ -H "Authorization: Bearer sk_live_9f3a...e21" \ -H "Content-Type: application/json" # Test key (sandbox) curl https://api.tradeops.io/v1/workflows \ -H "Authorization: Bearer sk_test_4b7c...a09"
import { TradeOps } from '@tradeops/sdk'; const client = new TradeOps({ apiKey: process.env.TRADEOPS_API_KEY, // sk_live_... or sk_test_... baseUrl: 'https://api.tradeops.io/v1' }); const workflows = await client.workflows.list();
import os from tradeops import TradeOps client = TradeOps( api_key=os.environ["TRADEOPS_API_KEY"], # sk_live_... or sk_test_... base_url="https://api.tradeops.io/v1" ) workflows = client.workflows.list()
Scopes
API keys are constrained by scopes. Request only the scopes your integration needs.
| Scope | Access |
|---|---|
| workflows:read | List and retrieve workflows and steps. |
| workflows:write | Create, update, delete, and reorder workflows and steps. |
| templates:read | List and retrieve templates. Install is covered by workflows:write. |
| documents:read | Retrieve standard trade documents as JSON or PDF. |
| webhooks:manage | Create, list, and delete webhooks. |
Never expose secret keys in client-side code. All requests must originate from a trusted server. If a key leaks, revoke it immediately from the workspace settings.
Base URL & Versioning
All requests target https://api.tradeops.io/v1. The version is pinned in the path so upgrades never break existing integrations.
| Environment | Base URL | Key prefix |
|---|---|---|
| Live | https://api.tradeops.io/v1 | sk_live_ |
| Test | https://api.tradeops.io/v1 | sk_test_ |
The test environment is a full sandbox: workflows you create, steps you add, and documents you generate stay isolated. No live customs filings or statutory submissions are triggered.
Quick Start
Create your first workflow, add a step, and retrieve the result in three requests.
1. Create a workflow
curl -X POST https://api.tradeops.io/v1/workflows \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "name": "Q2 Import Clearance", "type": "customs", "description": "Import entry lifecycle for Q2 shipments" }'
const wf = await client.workflows.create({ name: 'Q2 Import Clearance', type: 'customs', description: 'Import entry lifecycle for Q2 shipments' });
wf = client.workflows.create( name="Q2 Import Clearance", type="customs", description="Import entry lifecycle for Q2 shipments" )
2. Add a step
curl -X POST https://api.tradeops.io/v1/workflows/wf_8a2f9c/steps \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "title": "Prepare ISF filing", "phase": "Pre-arrival", "systems": ["ACE"], "docs": ["ISF 10+2"], "document_key": "isf_filing" }'
const step = await client.workflows.addStep('wf_8a2f9c', { title: 'Prepare ISF filing', phase: 'Pre-arrival', systems: ['ACE'], docs: ['ISF 10+2'], document_key: 'isf_filing' });
step = client.workflows.add_step( "wf_8a2f9c", title="Prepare ISF filing", phase="Pre-arrival", systems=["ACE"], docs=["ISF 10+2"], document_key="isf_filing" )
3. Retrieve the workflow
You've just made a complete create → add → read cycle. Every workflow you create in the API appears immediately in the Workflow Studio UI.
Errors
The API uses standard HTTP status codes plus a JSON error envelope. Every error response includes a machine-readable code, a human-readable message, and a request_id you can hand to support.
{ "error": { "code": "workflow_not_found", "message": "No workflow exists with id wf_missing", "request_id": "req_7f3a9b2c1d", "doc_url": "https://docs.tradeops.io/errors/workflow_not_found" } }
Status codes
| Status | Meaning | Typical causes |
|---|---|---|
| 200 OK | The request succeeded. | — |
| 201 Created | A new resource was created. | POST /workflows, POST /steps |
| 204 No Content | The resource was deleted. | DELETE /workflows/{id} |
| 400 Bad Request | Malformed request body or parameters. | Missing required field, invalid JSON |
| 401 Unauthorized | Missing or invalid API key. | Header not set, key revoked |
| 403 Forbidden | The key lacks the required scope. | workflows:read only, attempting write |
| 404 Not Found | The resource does not exist. | Invalid workflow_id |
| 409 Conflict | The request conflicts with current state. | Duplicate workflow name in workspace |
| 422 Unprocessable | Semantic validation failed. | Invalid workflow type, unreachable webhook URL |
| 429 Too Many Requests | Rate limit exceeded. | See Rate Limits. |
| 500 Server Error | Unexpected server-side failure. | Retry with backoff, contact support |
Error codes
| Code | Description |
|---|---|
| unauthorized | The API key is missing or invalid. |
| insufficient_scope | The key does not have the required scope. |
| workflow_not_found | No workflow exists with the supplied id. |
| step_not_found | No step exists with the supplied id. |
| invalid_workflow_type | The workflow type is not one of manufacturing, customs, freight, statutory. |
| duplicate_workflow_name | A workflow with the same name exists in this workspace. |
| invalid_document_key | The requested document template does not exist. |
| webhook_unreachable | The webhook URL failed the test delivery. |
| rate_limit_exceeded | Too many requests. Back off and retry. |
Rate Limits
Requests are rate-limited per API key. The limit depends on your plan tier and refreshes on a rolling 60-second window.
| Plan | Requests / minute | Burst |
|---|---|---|
| Developer | 60 | 120 |
| Team | 600 | 1,200 |
| Enterprise | 3,000 | 6,000 |
Every response includes the following headers:
X-RateLimit-Limit— the request limit for the current window.X-RateLimit-Remaining— requests left in the window.X-RateLimit-Reset— Unix timestamp when the window resets.Retry-After— seconds to wait before retrying (only on 429).
Use exponential backoff. On 429 or 5xx, wait 2^n seconds (capped at 60) before retrying. Do not retry in a tight loop.
Pagination
List endpoints use cursor-based pagination. Pass limit (max 100, default 20) and starting_after (the last id from the previous page) to page through results.
curl "https://api.tradeops.io/v1/workflows?limit=20&starting_after=wf_8a2f9c" \ -H "Authorization: Bearer sk_live_..."
Responses contain a data array plus a pagination object:
{ "data": [ /* ... */ ], "pagination": { "has_more": true, "next_cursor": "wf_8a2f9c", "total_count": 248 } }
Workflows API
Workflows are the top-level container in TradeOps. Each workflow has a type that determines its accent color, its template library, and the standard documents it exposes.
| Type | Description |
|---|---|
| manufacturing | Bonded production & FIZ lifecycle — purchase order through compliance report. |
| customs | Import entry lifecycle — ISF through entry summary reconciliation. |
| freight | Load lifecycle — intake through invoice settlement. |
| statutory | Malaysian statutory compliance — JTKSM, JIM, LHDN, EPF, SOCSO, FOMEMA. |
List workflows
Returns a paginated list of workflows in the current workspace. Optional query parameters filter by type and name.
Query parameters
| Name | Type | Description |
|---|---|---|
| typeoptional | string | Filter by workflow type: manufacturing, customs, freight, statutory. |
| limitoptional | integer | Number of results (1–100). Defaults to 20. |
| starting_afteroptional | string | Cursor — the id of the last workflow from the previous page. |
curl "https://api.tradeops.io/v1/workflows?type=customs&limit=50" \ -H "Authorization: Bearer sk_live_..."
const list = await client.workflows.list({ type: 'customs', limit: 50 });
list_ = client.workflows.list( type="customs", limit=50 )
Response
{ "data": [ { "id": "wf_8a2f9c", "name": "Q2 Import Clearance", "type": "customs", "description": "Import entry lifecycle for Q2 shipments", "step_count": 10, "created_at": "2026-03-14T08:00:00Z", "updated_at": "2026-03-16T12:34:00Z" } ], "pagination": { "has_more": false, "next_cursor": null, "total_count": 1 } }
Retrieve workflow
Returns a single workflow with its steps, ordered by their current position.
Path parameters
| Name | Type | Description |
|---|---|---|
| workflow_idrequired | string | The unique workflow identifier, e.g. wf_8a2f9c. |
curl https://api.tradeops.io/v1/workflows/wf_8a2f9c \ -H "Authorization: Bearer sk_live_..."
const wf = await client.workflows.get('wf_8a2f9c');
wf = client.workflows.get("wf_8a2f9c")
{ "id": "wf_8a2f9c", "name": "Q2 Import Clearance", "type": "customs", "description": "Import entry lifecycle for Q2 shipments", "created_at": "2026-03-14T08:00:00Z", "updated_at": "2026-03-16T12:34:00Z", "steps": [ { "id": "st_1", "position": 1, "title": "Prepare ISF filing", "phase": "Pre-arrival", "systems": ["ACE"], "docs": ["ISF 10+2"], "document_key": "isf_filing", "warn": "\$5,000 per late filing", "danger": true } ] }
Create workflow
Creates a new workflow. Workflow names must be unique within a workspace.
Body parameters
| Name | Type | Description |
|---|---|---|
| namerequired | string | Display name, 1–120 characters, unique per workspace. |
| typerequired | string | One of manufacturing, customs, freight, statutory. |
| descriptionoptional | string | Free-text description, max 500 characters. |
| template_keyoptional | string | If provided, seeds the workflow with the steps from a template. See Install template. |
curl -X POST https://api.tradeops.io/v1/workflows \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "name": "Q2 Import Clearance", "type": "customs", "description": "Import entry lifecycle for Q2 shipments", "template_key": "customs_default" }'
const wf = await client.workflows.create({ name: 'Q2 Import Clearance', type: 'customs', description: 'Import entry lifecycle for Q2 shipments', template_key: 'customs_default' });
wf = client.workflows.create( name="Q2 Import Clearance", type="customs", description="Import entry lifecycle for Q2 shipments", template_key="customs_default" )
Returns 201 Created with the full workflow object, including its seeded steps if template_key was supplied.
Update workflow
Updates the name, description, or type of a workflow. Only the supplied fields are modified.
Body parameters
| Name | Type | Description |
|---|---|---|
| nameoptional | string | New display name. |
| descriptionoptional | string | New description. Pass an empty string to clear. |
| typeoptional | string | Change the workflow type. Existing steps are preserved; only the accent and template library change. |
curl -X PATCH https://api.tradeops.io/v1/workflows/wf_8a2f9c \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "name": "Q2 Import Clearance (revised)" }'
const wf = await client.workflows.update('wf_8a2f9c', { name: 'Q2 Import Clearance (revised)' });
wf = client.workflows.update( "wf_8a2f9c", name="Q2 Import Clearance (revised)" )
Delete workflow
Permanently deletes a workflow and all of its steps. This action cannot be undone.
Irreversible. Deleting a workflow also deletes every step and unlinks every generated document. If you only want to archive it, set name to a prefixed value or move it to a different workspace.
curl -X DELETE https://api.tradeops.io/v1/workflows/wf_8a2f9c \ -H "Authorization: Bearer sk_live_..."
await client.workflows.delete('wf_8a2f9c');
client.workflows.delete("wf_8a2f9c")
Returns 204 No Content on success.
Steps API
Steps are the individual stages inside a workflow. Each step has a phase, one or more systems, one or more documents, and a description of what actually happens in real life.
| Field | Type | Description |
|---|---|---|
| id | string | Step identifier, e.g. st_1. |
| position | integer | 1-based order within the workflow. |
| title | string | Display title. |
| phase | string | Lifecycle phase label, e.g. "Pre-arrival". |
| systems | string[] | Systems involved (ACE, ABI, TMS, DAT, …). |
| docs | string[] | Document names attached to the step. |
| document_key | string | null | Links to a standard document template. |
| warn | string | Optional warning chip text. |
| danger | boolean | Whether the warning is critical. |
| reality | string | Description of what actually happens in this step. |
List steps
Returns all steps for a workflow, ordered by position.
curl https://api.tradeops.io/v1/workflows/wf_8a2f9c/steps \ -H "Authorization: Bearer sk_live_..."
Create step
Appends a new step to the end of the workflow.
Body parameters
| Name | Type | Description |
|---|---|---|
| titlerequired | string | Step title, 1–200 characters. |
| phaseoptional | string | Phase label. |
| systemsoptional | string[] | Systems attached to the step. |
| docsoptional | string[] | Document names. |
| document_keyoptional | string | Links to a standard template. See Documents. |
| warnoptional | string | Warning chip text. |
| dangeroptional | boolean | Marks the warning as critical. Defaults to false. |
| realityoptional | string | Description of what happens in this step. |
curl -X POST https://api.tradeops.io/v1/workflows/wf_8a2f9c/steps \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "title": "Coordinate manifest data", "phase": "Pre-arrival", "systems": ["AMS via ACE"], "docs": ["Carrier manifest"], "reality": "Carrier transmits the manifest 24 hours before loading." }'
const step = await client.workflows.addStep('wf_8a2f9c', { title: 'Coordinate manifest data', phase: 'Pre-arrival', systems: ['AMS via ACE'], docs: ['Carrier manifest'], reality: 'Carrier transmits the manifest 24 hours before loading.' });
step = client.workflows.add_step( "wf_8a2f9c", title="Coordinate manifest data", phase="Pre-arrival", systems=["AMS via ACE"], docs=["Carrier manifest"], reality="Carrier transmits the manifest 24 hours before loading." )
Update step
Partially updates a step. Only the supplied fields are modified; the others retain their current values.
curl -X PATCH https://api.tradeops.io/v1/workflows/wf_8a2f9c/steps/st_2 \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "warn": "24-hour deadline", "danger": true }'
await client.workflows.updateStep('wf_8a2f9c', 'st_2', { warn: '24-hour deadline', danger: true });
client.workflows.update_step( "wf_8a2f9c", "st_2", warn="24-hour deadline", danger=True )
Delete step
Removes a step and re-indexes the positions of the remaining steps.
curl -X DELETE https://api.tradeops.io/v1/workflows/wf_8a2f9c/steps/st_2 \ -H "Authorization: Bearer sk_live_..."
await client.workflows.deleteStep('wf_8a2f9c', 'st_2');
client.workflows.delete_step("wf_8a2f9c", "st_2")
Returns 204 No Content on success.
Reorder steps
Applies a new order to the steps in a workflow in a single request. The array must contain every step id in the workflow exactly once.
Body parameters
| Name | Type | Description |
|---|---|---|
| orderrequired | string[] | Step ids in their new order, from first to last. |
curl -X POST https://api.tradeops.io/v1/workflows/wf_8a2f9c/steps/reorder \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "order": ["st_3", "st_1", "st_2"] }'
await client.workflows.reorderSteps('wf_8a2f9c', { order: ['st_3', 'st_1', 'st_2'] });
client.workflows.reorder_steps( "wf_8a2f9c", order=["st_3", "st_1", "st_2"] )
Templates API
Templates are curated workflows maintained by TradeOps. The four built-in templates — manufacturing, customs, freight, and statutory — can be installed into any workspace.
List templates
Returns the template library. Every template carries its type, its step count, and a preview of its first three steps.
curl https://api.tradeops.io/v1/templates \ -H "Authorization: Bearer sk_live_..."
const templates = await client.templates.list();
templates = client.templates.list(){ "data": [ { "key": "manufacturing_default", "name": "Manufacturing & FIZ", "type": "manufacturing", "step_count": 12, "description": "Bonded production lifecycle" }, { "key": "customs_default", "name": "Customs broker", "type": "customs", "step_count": 10, "description": "Import entry lifecycle" }, { "key": "freight_default", "name": "Freight broker", "type": "freight", "step_count": 8, "description": "Load lifecycle" }, { "key": "statutory_default", "name": "Malaysian statutory", "type": "statutory", "step_count": 6, "description": "Statutory compliance calendar" } ] }
Retrieve template
Returns the full step list for a template, ready to be installed.
curl https://api.tradeops.io/v1/templates/customs_default \ -H "Authorization: Bearer sk_live_..."
const tpl = await client.templates.get('customs_default');
tpl = client.templates.get("customs_default")
Install template
Copies every step from a template into an existing workflow. By default, existing steps are preserved and the template steps are appended; pass replace: true to clear first.
Body parameters
| Name | Type | Description |
|---|---|---|
| template_keyrequired | string | One of the template keys returned by List templates. |
| replaceoptional | boolean | If true, deletes existing steps first. Defaults to false. |
curl -X POST https://api.tradeops.io/v1/workflows/wf_8a2f9c/install-template \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "template_key": "customs_default", "replace": true }'
await client.workflows.installTemplate('wf_8a2f9c', { template_key: 'customs_default', replace: true });
client.workflows.install_template( "wf_8a2f9c", template_key="customs_default", replace=True )
Documents API
Standard trade documents are available as structured JSON or as generated PDFs. Each step in a workflow can reference a document template by key — the same keys used across the whole TradeOps platform.
Available document keys
| Key | Label | Category |
|---|---|---|
| purchase_order | Purchase Order | Manufacturing |
| bonded_entry | Bonded Entry Declaration | Manufacturing |
| quality_inspection | Incoming Quality Inspection | Manufacturing |
| bonded_ledger | Bonded Stock Ledger | Manufacturing |
| rwa_token | RWA Tokenization Certificate | Manufacturing |
| isf_filing | Importer Security Filing (ISF-10) | Customs |
| cbp_3461 | CBP Form 3461 | Customs |
| cbp_7501 | CBP Form 7501 | Customs |
| bill_of_lading | Ocean Bill of Lading | Customs |
| certificate_of_origin | Certificate of Origin | Customs |
| rate_confirmation | Rate Confirmation | Freight |
| freight_bol | Freight Bill of Lading | Freight |
| pod | Proof of Delivery | Freight |
| epf_form_a | EPF Form A (KWSP) | Statutory |
| socso_form_2 | SOCSO Form 2 (PERKESO) | Statutory |
| lhdn_form_e | LHDN Form E | Statutory |
| plks | PLKS — Temporary Employment Pass | Statutory |
| fomema | FOMEMA Registration | Statutory |
List documents
Returns every document template available in the workspace, with its key, label, and category.
curl https://api.tradeops.io/v1/documents \ -H "Authorization: Bearer sk_live_..."
const docs = await client.documents.list();
docs = client.documents.list()Retrieve document
Returns the document template as structured JSON: metadata, fields, table rows, signatures, and footer.
curl https://api.tradeops.io/v1/documents/cbp_7501 \ -H "Authorization: Bearer sk_live_..."
const doc = await client.documents.get('cbp_7501');
doc = client.documents.get("cbp_7501")
{ "key": "cbp_7501", "label": "CBP Form 7501 — Entry Summary", "agency": "U.S. Customs and Border Protection", "form_title": "ENTRY SUMMARY", "form_sub": "CBP Form 7501", "meta": { "Entry No.": "7TQ-004281-3", "OMB No.": "1651-0022" }, "fields": [ { "label": "Filer Code / Entry No.", "value": "7TQ-004281-3" }, { "label": "Entry Type", "value": "01" } ], "table": { "head": ["Line", "Description", "HTSUS", "Entered Value", "Duty"], "rows": [ ["001", "Aluminium housing", "7616.99.5190", "11,640.00", "291.00"] ], "total": ["", "TOTAL", "", "17,676.00", "359.04"] }, "signatures": [ { "label": "IMPORTER OF RECORD", "script": "TradeOps Distribution Inc." } ] }
Generate PDF
Renders the document as a print-ready PDF and returns a signed download URL valid for 5 minutes. Optionally supply overrides to fill fields with live data from your system.
Body parameters
| Name | Type | Description |
|---|---|---|
| overridesoptional | object | Map of field labels to replacement values. Useful for stamping live PO numbers, B/L numbers, or invoice amounts. |
| paperoptional | string | a4 (default) or letter. |
| include_stampoptional | boolean | Whether to include the red "APPROVED / RELEASED / FILED" stamp. Defaults to true. |
curl -X POST https://api.tradeops.io/v1/documents/cbp_7501/pdf \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "overrides": { "Entry No.": "7TQ-009912-1", "Summary Date": "15 MAR 2026" }, "paper": "letter", "include_stamp": true }'
const pdf = await client.documents.pdf('cbp_7501', { overrides: { 'Entry No.': '7TQ-009912-1', 'Summary Date': '15 MAR 2026' }, paper: 'letter', include_stamp: true });
pdf = client.documents.pdf( "cbp_7501", overrides={ "Entry No.": "7TQ-009912-1", "Summary Date": "15 MAR 2026" }, paper="letter", include_stamp=True )
{ "id": "pdf_4c8b2f91", "document_key": "cbp_7501", "url": "https://files.tradeops.io/pdf/pdf_4c8b2f91?token=...", "expires_at": "2026-03-15T12:05:00Z", "size_bytes": 184320 }
Webhooks
Webhooks let you receive real-time HTTP callbacks when workflows change, documents are generated, or statutory deadlines approach. Every delivery is signed with HMAC-SHA256 using your endpoint's signing secret.
List webhooks
Returns every webhook configured for the workspace.
curl https://api.tradeops.io/v1/webhooks \ -H "Authorization: Bearer sk_live_..."
Create webhook
Registers a new webhook endpoint. TradeOps sends a test event immediately; the webhook stays inactive until that test succeeds.
Body parameters
| Name | Type | Description |
|---|---|---|
| urlrequired | string | HTTPS endpoint. Must respond 200 within 5 seconds. |
| eventsrequired | string[] | Event names to subscribe to. See Event types. |
| descriptionoptional | string | Free-text description. |
curl -X POST https://api.tradeops.io/v1/webhooks \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "url": "https://api.acme.com/tradeops/webhook", "events": ["workflow.updated", "document.generated", "deadline.approaching"] }'
const wh = await client.webhooks.create({ url: 'https://api.acme.com/tradeops/webhook', events: ['workflow.updated', 'document.generated', 'deadline.approaching'] });
wh = client.webhooks.create( url="https://api.acme.com/tradeops/webhook", events=["workflow.updated", "document.generated", "deadline.approaching"] )
The response includes a signing_secret that is shown only once. Store it securely — you'll need it to verify the X-TradeOps-Signature header on every delivery.
Delete webhook
Removes the webhook and stops all deliveries. Pending retries are dropped.
curl -X DELETE https://api.tradeops.io/v1/webhooks/wh_2f9a8c \ -H "Authorization: Bearer sk_live_..."
Event types
Webhook payloads share a common envelope. The type field tells you which event fired.
| Event | Fires when |
|---|---|
| workflow.created | A new workflow is created. |
| workflow.updated | A workflow's name, type, or description changes. |
| workflow.deleted | A workflow is deleted. |
| step.created | A step is added to a workflow. |
| step.updated | A step's fields change. |
| step.deleted | A step is removed. |
| document.generated | A PDF is generated for a document template. |
| deadline.approaching | A statutory deadline is 7, 3, or 1 day away. |
{ "id": "evt_9a2f3c81", "type": "workflow.updated", "created_at": "2026-03-16T12:34:00Z", "workspace_id": "ws_acme", "data": { "workflow_id": "wf_8a2f9c", "changes": { "name": { "from": "Q2 Import Clearance", "to": "Q2 Import Clearance (revised)" } } } }
Signature verification
Every delivery includes an X-TradeOps-Signature header with an HMAC-SHA256 of the raw request body, using your endpoint's signing secret. Verify it before processing:
import crypto from 'node:crypto'; function verifySignature(rawBody, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) ); }
import hmac import hashlib def verify_signature(raw_body, signature, secret): expected = hmac.new( secret.encode(), raw_body.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature)
SDKs & Libraries
First-party SDKs wrap the entire API surface with idiomatic clients. Use them to avoid hand-rolling authentication, retries, and pagination.
| Language | Package | Install |
|---|---|---|
| Node.js | @tradeops/sdk | npm install @tradeops/sdk |
| Python | tradeops | pip install tradeops |
| Go | github.com/tradeops/go-sdk | go get github.com/tradeops/go-sdk |
| Java | io.tradeops:sdk | implementation 'io.tradeops:sdk:1.4.0' |
Changelog
v1.4 — March 2026
- Added
POST /documents/{key}/pdffor server-side PDF generation. - Added
document_keyfield to steps. - Added
deadline.approachingwebhook event. - Deprecated
GET /documents/{key}/renderin favour of the new PDF endpoint.
v1.3 — January 2026
- Added reorder endpoint
POST /workflows/{id}/steps/reorder. - Renamed
POST /workflows/{id}/templatetoinstall-template. - Added
total_countto paginated responses.
v1.2 — November 2025
- Initial public release with workflows, steps, templates, and webhooks.
