Skip to main content

Operation calls

Call OpenAPI operations using the call syntax with operation IDs.

Basic syntax

call SourceName.operationId
call SourceName.operationId { options }

Simple calls

GET operations

// OpenAPI: GET /pets with operationId: listPets
call Petstore.listPets

// OpenAPI: GET /pets/{petId} with operationId: getPetById
call Petstore.getPetById { params: { petId: "123" } }

POST operations

// OpenAPI: POST /pets with operationId: addPet
call Petstore.addPet {
body: {
name: "Fluffy",
tag: "cat"
}
}

PUT/PATCH operations

// PUT - full replacement
call API.updateItem {
params: { id: "123" },
body: { name: "New Name", status: "active" }
}

// PATCH - partial update
call API.patchItem {
params: { id: "123" },
body: { status: "inactive" }
}

DELETE operations

call API.deleteItem {
params: { id: "123" }
}

Parameters

Path parameters

For /pets/{petId}:

call Petstore.getPetById {
params: { petId: "123" }
}
// Generates: GET /pets/123

Query parameters

For /pets?limit=10&status=available:

call Petstore.listPets {
params: {
limit: 10,
status: "available"
}
}

Combined parameters

call API.listUserOrders {
params: {
userId: "123", // Path: /users/{userId}/orders
status: "pending", // Query: ?status=pending
limit: 50 // Query: ?limit=50
}
}
// Generates: GET /users/123/orders?status=pending&limit=50

Request body

Simple body

call API.createItem {
body: {
name: "Test Item",
price: 29.99
}
}

Dynamic body

for item in items {
call API.createItem {
body: {
name: item.name,
price: item.price,
metadata: {
source: "sync",
timestamp: now()
}
}
}
}

From variable

map data -> Payload {
name: .name,
status: "active"
}

call API.createItem { body: data }

Headers

Custom headers

call API.listItems {
headers: {
"X-Request-ID": uuid(),
"Accept-Language": "en-US"
}
}

Tenant headers

call Xero.listInvoices {
headers: {
"Xero-Tenant-Id": env("XERO_TENANT_ID")
}
}

Pagination with operations

call API.listItems {
params: { limit: 100 },
paginate: offset(offset, 100),
until: length(response.items) == 0
}

Cursor pagination

call API.listItems {
paginate: cursor(cursor, 100, "meta.nextCursor"),
until: response.meta.nextCursor == null
}

Combining options

call API.searchItems {
params: {
query: "test",
limit: 50
},
headers: {
"X-Custom": "value"
},
paginate: cursor(after, 50, "pageInfo.endCursor"),
until: response.pageInfo.hasNextPage == false,
retry: {
maxAttempts: 3,
backoff: exponential
}
}

Response handling

action FetchWithHandling {
call API.getItem { params: { id: itemId } }

match response {
{ data: item } -> store item -> items { key: .id },
{ error: e } -> abort e,
_ -> abort "Unexpected response"
}
}

Operation chaining

action CreateAndFetch {
// Create
call API.createItem {
body: { name: "New Item" }
}

// response.id from creation
call API.getItem {
params: { id: response.id }
}

store response -> items { key: .id }
}

Error handling

call API.riskyOperation { params: { id: "123" } }

match response {
{ code: 400 } -> abort "Invalid request",
{ code: 401 } -> jump RefreshToken then retry,
{ code: 404 } -> skip,
{ code: 429 } -> retry { delay: 60000 },
{ code: 500 } -> retry { maxAttempts: 3 },
_ -> continue
}

Dynamic operation calls

Based on condition

action SmartSync {
call API.checkItem { params: { id: item.id } }

match response {
{ exists: false } -> {
call API.createItem { body: item }
},
{ exists: true, needsUpdate: true } -> {
call API.updateItem { params: { id: item.id }, body: item }
},
_ -> continue
}
}

Best practices

Match Operation IDs

# In OpenAPI spec
operationId: listUsers # camelCase recommended
call API.listUsers  # Match exactly

Use descriptive operations

# Good
operationId: createInvoice
operationId: getInvoiceById
operationId: listInvoicesByCustomer

# Avoid
operationId: post1
operationId: get2

Handle all response codes

call API.operation

match response {
{ code: 200 } -> continue,
{ code: 201 } -> continue,
{ code: 204 } -> continue,
{ code: 400 } -> abort "Bad request",
{ code: 401 } -> jump RefreshAuth then retry,
{ code: 404 } -> skip,
{ code: 500 } -> retry { maxAttempts: 3 },
_ -> abort "Unexpected response"
}