From Provider Call to Application Capability

A useful test of Corsair is whether a reader can follow one connected action without treating the API call, the credential, the database row, and the public connection flow as unrelated features. Consider a support application that must send a Slack message and show the result on a ticket page. Tracing that action across Corsair’s boundaries makes the architecture—and the places it can fail—more concrete than a list of features.

A message that crosses four boundaries

The action begins in the application, not in Slack. A user clicks a button or asks an application feature to notify a support channel. The application selects a provider operation such as a Slack message post and supplies arguments that match the plugin’s typed contract. At this point, the application owns the business decision: it knows why the message should be sent, which ticket it belongs to, and which user or workspace is making the request. Corsair owns the integration lifecycle around that decision; Slack still owns the message once the provider accepts it.

The first boundary is the plugin contract. The public operation has a stable Corsair shape, but its arguments and response are Slack-specific. The plugin’s endpoint implementation knows how to form the provider request, while its schemas and metadata describe the operation to application code and other consumers. The application should not need to hand-build Slack headers, parse an untyped response, or implement a second copy of the integration’s endpoint tree. It does need to use the provider’s actual channel identifiers and message semantics.

The second boundary is account and key resolution. Before the request can leave the application, Corsair must determine which connected account gives it authority to post. In a single-tenant tool, that may be the default account. In a product that serves connected users, it must be the account associated with the active tenant. The plugin’s key builder retrieves the appropriate stored credential, and an OAuth path may check expiry or refresh before continuing. If no usable credential exists, the action has not failed as a Slack API error; it has entered connection recovery.

The third boundary is the provider call itself. Corsair sends the live operation to Slack and receives a provider response. A rate limit, network error, or provider validation failure can be handled through the configured error path and retry strategy. A successful response means Slack accepted the operation, not that the application has completed all of its own work. The application may still need to associate the returned message with its support ticket, and it may need to decide what to do if the provider response is incomplete or a later local write fails.

The fourth boundary is local state. Corsair can upsert the provider response into its entity projection. The ticket page can then read the local Slack entity through .db, alongside the application’s own ticket and note data. The application does not need to merge the API response into a separate UI cache just to make the message appear. It can reread the common local representation that webhook processing may update later.

flowchart LR User[User or application feature] --> Call[Typed Corsair operation] Call --> Scope[Account and key resolution] Scope --> Provider[External provider] Provider --> Entity[Entity upsert] Entity --> Read[Application local read] Scope -. missing or expired .-> Recover[Connect or refresh] Provider -. transient error .-> Retry[Retry or fail] Hub[Hub public relay] -. connection result .-> Recover