Loading

Custom API Functions

Endpoints of your own design, on top of the ones generated from your datastores, for operations the generated CRUD cannot express.

Custom API Functions

Your datastores already produce endpoints. A custom API function adds one of your own design, at a path and method you choose.

Where to find it

Architect Panel → Integration & Connections:

  • API Server — the custom functions and their actions
  • OpenAPI Specification — where your endpoint appears alongside the generated ones

Architect Panel → Data:

  • Datastores — the generated endpoints these supplement

What one is

  • A name.
  • A path.
  • An HTTP method — GET, POST, PUT, DELETE or PATCH.

Beneath it sit one or more actions, which are what the endpoint actually does when it is called.

Check you need one first

Most integration requirements are met by the generated endpoints, and a custom function is a thing you then own and maintain. Before building one, ask whether the caller could achieve the same with the endpoints that already exist.

The honest test: if a custom function would just be "fetch these rows", it is not earning its place.

When one is genuinely warranted

  • An operation spanning several datastores that should succeed or fail as a unit.
  • A caller you cannot change, that expects a particular shape.
  • An action rather than a record — something the API should do, not something it should return.
  • A deliberately narrow endpoint for an external party, exposing exactly one operation.

That last is a good pattern: rather than granting a partner access to a datastore, give them one endpoint that does one thing.

Choose the method honestly

Use GET for reads, POST to create, PUT and PATCH to update, DELETE to remove. Callers, proxies and caches all make assumptions from the method — a GET that changes data will eventually be retried or cached by something in the middle, with results nobody intended.

Paths should not collide

Keep custom paths clearly distinguishable from generated ones so nobody has to guess which they are calling. A prefix for your own endpoints makes the spec far easier to read.

Permissions still apply

A custom function runs as the calling key's identity, so the underlying data access is governed the same way. It is not a route around permissions — but it can easily be a route around your intent if it does something broader than the caller could do directly.

Look at what the actions touch, not just at what the endpoint is called.

They appear in the spec

Custom endpoints show up in the OpenAPI specification alongside the generated ones, so an integrator sees one description of everything available.

Document what it does

A generated endpoint is self-explanatory from the datastore. A custom one is not — it does whatever its actions do, and the next person will not be able to infer that from its name. Write down the intent, the expected body and what it returns.

Worked example

A partner needs to submit a referral, which creates a record in one datastore, a contact in another and a task for a team. As three generated calls it is three round trips that can half-fail. One custom endpoint takes the referral, performs all three, and returns the new reference — and the partner is granted nothing else.

Recommendations

  • Prove the generated endpoints cannot do it first.
  • One narrow endpoint per external operation, rather than broad datastore access.
  • Match the HTTP method to the effect.
  • Document the intent — the name will not carry it.

Custom Function Actions

An endpoint's actions are what it does. One custom function can carry several, performed in order.

Where to find it

Architect Panel → Integration & Connections:

  • API Server — custom functions and their actions

Architect Panel → Data:

  • Datastores — what the actions read and write
  • Data Extraction — one of the available action types

Composing an endpoint

Add actions in the order they should run. A referral endpoint might create a record, then create a linked contact, then hand the payload to extraction — three actions, one call from the caller's point of view.

Keep the sequence short

Every action is something that can fail, and a long chain multiplies both the failure modes and the difficulty of explaining what happened. If an endpoint is accumulating actions, that is usually a sign the operation wants to be a background process rather than a synchronous call.

Think about partial failure before you build

This is the part most worth planning. If the third action fails after the first two succeeded, what should the caller see, and what state is the data in?

Decide deliberately:

  • Order actions so the most likely failure happens first, before anything has been written.
  • Validate up front rather than discovering a problem midway.
  • Where a half-completed state is genuinely unacceptable, reconsider whether this should be one endpoint at all.

An endpoint that returns an error after having created two records is worse than one that fails cleanly, because the caller will retry and create them again.

Return something useful

A caller usually needs the reference of what was created, not just a success. Design the response as deliberately as the request — an integrator who has to make a second call to find out what they just created will ask you why.

Callbacks are code you own

Where an action runs a callback, that is your code running on every call to the endpoint. It gets the same care as anything else on that path: keep it fast, handle its own errors, and do not let it become the place business rules quietly accumulate where nobody looks for them.

Extraction as an action

Handing a payload to data extraction is a good fit when the caller sends structured data destined for a datastore — the mapping and transformations live in the extraction definition rather than in the endpoint, where they are visible and adjustable without changing the API.

Test the whole endpoint, not each action

Actions that each work individually can still fail in sequence — the second depending on something the first did not produce, or an ordering assumption that only holds sometimes. Call the endpoint as a caller would, including with input you expect to be rejected.

Log enough to diagnose

When a partner reports the endpoint failing, the inbound request log gives the outcome and timing. Whether that is enough to explain it depends on what your actions record — worth thinking about while building, not while somebody waits.

Worked example

A referral endpoint validates the payload first, then creates the referral, then the contact, then queues a task. The validation-first ordering means a malformed submission fails having written nothing, so the partner can simply resend. In six months the only failures have been validation ones, which is the outcome the ordering was chosen for.

Recommendations

  • Validate first, so failures happen before writes.
  • Keep chains short — long ones want to be background work.
  • Return the references you created.
  • Test the endpoint end to end, including rejections.