Type to search pages and rules.

Browse pages

External Integrations

External systems are unreliable and outside application change control.

Markdown17 provisions

Intent#

External systems are unreliable and outside application change control. This extension keeps provider details in Infrastructure, maps failures to project-owned outcomes, and tests network boundaries.

Activation#

Activation scope: local.

Applicable specification kinds: use-case, rule, journey.

The consumer enables integrations for each use case that calls or publishes to an external service, receives a webhook, or uses a provider SDK.

Baseline relationship#

This extension replaces no baseline provision.

This extension switches on no optional record type.

Standards#

Define business-action ports#

ruleguidance

Requirement Application MUST own a public external-service interface named for its business action.

Rationale A business port states the behavior that a use case needs without naming its provider.

Example IPaymentAuthorizer describes the business action without exposing a payment-provider client.

litespec/ext/integrations#define-business-action-ports

Isolate provider implementations#

rulecheckable

Requirement Infrastructure MUST own provider clients, SDKs, authentication, and transport models.

Rationale Provider-specific names and contracts remain outside Application's business boundary.

Example IStripeClient is provider infrastructure rather than an Application port.

litespec/ext/integrations#isolate-provider-implementations

Bind client configuration#

rulecheckable

Requirement An external client MUST bind its base address, credentials, timeout, and policy through validated options.

Rationale Validated options make provider configuration explicit at startup.

litespec/ext/integrations#bind-client-configuration

Use managed HTTP clients#

rulecheckable

Requirement An HTTP integration MUST use HttpClientFactory and applicable service discovery.

Rationale Managed client construction centralizes handler lifetime and service resolution.

litespec/ext/integrations#use-managed-http-clients

Reject per-request HTTP clients#

rulecheckable

Requirement An HTTP integration MUST NOT construct a new HTTP client for each request.

Rationale Per-request clients lose central handler configuration and can exhaust network resources.

litespec/ext/integrations#reject-per-request-http-clients

Bound transient retries#

rulecheckable

Requirement An external client MUST retry transient failures with bounded attempts and jitter.

Rationale Bounded jittered retries reduce synchronized retry load on an unavailable provider.

litespec/ext/integrations#bound-transient-retries

Protect non-idempotent calls#

rulecheckable

Requirement An external client MUST NOT retry a non-idempotent provider call without provider idempotency and documented replay behavior.

Rationale Repeated provider calls can duplicate irreversible external effects.

litespec/ext/integrations#protect-non-idempotent-calls

Translate provider failure outcomes#

rulecheckable

Requirement An integration MUST map provider errors to project-owned outcomes and stable diagnostics.

Rationale Project-owned outcomes remain stable when provider responses or SDK types change.

The project's own error catalog holds the stable codes. litespec/backend/api#return-stable-problem-details returns a code from that catalog. An integration that invents one code per provider creates one code space per provider. A client that branches on failure learns every code space. A provider's own error taxonomy is the input to the mapping, not its output.

Example A declined card and a declined direct debit both map to the project's payment-refused code. The provider's own code travels in diagnostics.

litespec/ext/integrations#translate-provider-failure-outcomes

Exclude provider internals#

rulecheckable

Requirement An API MUST NOT expose provider bodies, credentials, headers, exception types, or internal account identifiers.

Rationale Provider internals can disclose secrets, implementation details, or another account's data.

litespec/ext/integrations#exclude-provider-internals

Verify inbound provider messages#

rulecheckable

Requirement An inbound provider handler MUST verify signature, timestamp tolerance, replay protection, content type, size, schema, and event identity before processing.

Rationale Each check protects a different part of the trust boundary for a provider message.

Order matters here. Verify the signature first, over the raw body, before parsing the body or running any other check. An unauthenticated caller can reach a parser that runs first. A deserialized body is no longer the bytes that the signature covered. Stripe's signature guidance states the same requirement.

Example A failed signature returns 401 with no body. A message that names the failed check tells an unauthenticated caller how to pass it.

litespec/ext/integrations#verify-inbound-provider-messages

Process duplicate messages safely#

rulecheckable

Requirement An inbound provider handler MUST store or process duplicate events idempotently.

Rationale Provider delivery can repeat one event after a timeout or acknowledgement failure.

litespec/ext/integrations#process-duplicate-messages-safely

Reject formula-leading import values#

rulecheckable

Requirement A CSV or spreadsheet import MUST reject or neutralize a value that begins with a formula-leading character.

Rationale The formula-leading characters are the equals sign, the plus sign, the minus sign, the at sign, the tab, and the carriage return. Escaping when you export protects the reader of that export. It does not protect the reader of the next export. A different report can re-export an unchanged imported value without escaping it. CSV injection travels through the store, so the boundary that admits the value is where it stops.

Example An import that rejects the value reports the row and the field. An import that neutralizes it records what it changed. A silently altered value is a data defect the owner cannot see.

litespec/ext/integrations#reject-formula-leading-import-values

Simulate integration boundaries#

rulecheckable

Requirement An integration test MUST use WireMock.Net or a protocol-specific local endpoint.

Rationale A controllable endpoint exercises the network contract without a live provider account.

litespec/ext/integrations#simulate-integration-boundaries

Cover provider failure modes#

rulecheckable

Requirement An integration test MUST cover timeout, connection failure, transient response, permanent response, malformed payload, rate limit, duplicate delivery, and unexpected response shape.

Rationale Each failure mode can affect retry, mapping, or idempotency behavior.

An unexpected response shape is the mode a provider produces without failing. A well-formed response can carry a field that moved, a type that changed, or a value no one planned for. The response parses. The behavior is still wrong. Every other listed mode reports that response as an error. A provider that versions its API changes shape on a schedule. A pinned version still changes on the day the provider raises it.

litespec/ext/integrations#cover-provider-failure-modes

Conventions#

Group provider code#

conventionguidance

Default Place provider code under Infrastructure/Integrations/{Provider}/.

Replacement A consumer records a departure from this default as an Exception record with reason, review date, and removal condition.

Rationale One provider folder gives transport code a clear Infrastructure boundary.

litespec/ext/integrations#group-provider-code

Keep provider components together#

conventionguidance

Default Keep one options class, client, transport models, mappings, and registration module in each provider folder.

Replacement A consumer records a departure from this default as an Exception record with reason, review date, and removal condition.

Rationale Related provider implementation details remain discoverable together.

litespec/ext/integrations#keep-provider-components-together

Keep ports near use cases#

conventionguidance

Default Keep business-action ports with their Application use cases.

Replacement A consumer records a departure from this default as an Exception record with reason, review date, and removal condition.

Rationale The use case states why it needs the external behavior.

litespec/ext/integrations#keep-ports-near-use-cases

Dependencies#

  • Microsoft.Extensions.Http.Resilience
  • WireMock.Net in integration tests

Verification#

IDMarkEvidence
litespec/ext/integrations#define-business-action-portsguidanceDoes each Application port name a business action without naming its provider?
litespec/ext/integrations#isolate-provider-implementationscheckableExternalPortTests assert the Application assembly references no provider SDK or transport type.
litespec/ext/integrations#bind-client-configurationcheckableExternalClientTests reject missing or invalid external client configuration.
litespec/ext/integrations#use-managed-http-clientscheckableExternalClientTests assert HTTP registration uses the owned factory and declared discovery path.
litespec/ext/integrations#reject-per-request-http-clientscheckableExternalClientTests report no per-request HTTP client construction.
litespec/ext/integrations#bound-transient-retriescheckableExternalRetryTests verify bounded jittered retry for transient failures.
litespec/ext/integrations#protect-non-idempotent-callscheckableExternalRetryTests show no retry without documented provider protection.
litespec/ext/integrations#translate-provider-failure-outcomescheckableExternalFailureTests assert provider failures map to project-owned outcomes and stable diagnostics.
litespec/ext/integrations#exclude-provider-internalscheckableExternalFailureTests expose no provider body, credential, header, type, or account identifier.
litespec/ext/integrations#verify-inbound-provider-messagescheckableExternalInboundTests reject invalid signatures, timestamps, content, size, schema, and identities.
litespec/ext/integrations#process-duplicate-messages-safelycheckableExternalInboundTests leave one accepted external effect.
litespec/ext/integrations#reject-formula-leading-import-valuescheckableExternalInboundTests reject or neutralize formula-leading import values.
litespec/ext/integrations#simulate-integration-boundariescheckableExternalTestTests run each provider contract against a controllable local endpoint.
litespec/ext/integrations#cover-provider-failure-modescheckableExternalTestTests suite covers every declared failure mode.
litespec/ext/integrations#group-provider-codeguidanceDoes each provider folder hold its code or record an Exception?
litespec/ext/integrations#keep-provider-components-togetherguidanceDoes each provider folder hold its options, client, models, mappings, and registration?
litespec/ext/integrations#keep-ports-near-use-casesguidanceDoes each business-action port stay with its owning Application use case?