# Build a provider adapter

This recipe connects an external carrier API to a One-owned shipment operation
without letting the carrier own the application contract.

The `.one` and Rust APIs below are illustrative end-product syntax.

## 1. Keep the domain operation independent

```one
one 1

semantic parcelhub.shipping
    domain one.contracts@1
    operation CreateShipment@1
        input ShipmentRequest
        output Shipment
        faults [AddressRejected, ServiceUnavailable]
        effect external_create(shipment)
        idempotency caller_key(input.request_id)
        outcome query ShipmentStatus.GetByRequest
        authority shipment:create
```

Carrier product names, URLs, headers, credentials, and response codes do not
enter this contract.

## 2. Publish a bounded realization claim

```one
semantic acme_carrier.provider
    domain one.providers@1
    realization AcmeShipmentCreate@1
        provides parcelhub.shipping#CreateShipment@1
        target process_remote
        protocol https_json

        supports idempotency caller_key
        supports outcome_lookup by_request_id
        supports cancellation before_dispatch

        requires secret acme_carrier_api_key
        requires outbound_origin https("api.carrier.example")
        requires region [eu]
```

Publication makes the claim eligible for governed catalog admission. It does
not select the provider, create a binding, read a credential, or authorize an
external effect.

## 3. Keep the adapter thin

```rust,ignore
pub async fn create_shipment(
    ctx: CarrierContext,
    request: ShipmentRequest,
) -> Result<Shipment, CarrierBoundaryFault> {
    let wire = AcmeCreateRequest::project(&request)?;
    let response = ctx
        .http()
        .post(ctx.endpoint().shipments())
        .idempotency_key(request.request_id)
        .json(wire)
        .send()
        .await?;

    AcmeCreateResponse::lower(response)
}
```

Typed projection owns the external wire format and reports loss. The adapter
maps protocol behavior and evidence; it does not copy generic HTTP lifecycle,
secret delivery, retry, timeout, or observation machinery.

## 4. Reconcile unknown outcomes

```rust,ignore
pub async fn observe(
    ctx: CarrierContext,
    request_id: ShipmentRequestId,
) -> Result<ProviderObservation<Shipment>, CarrierBoundaryFault> {
    let response = ctx.http().get(ctx.endpoint().by_request(request_id)).send().await?;
    AcmeShipmentObservation::lower(response)
}
```

An observation is linked to the original external effect. It does not rewrite
the attempt or become a One fact merely because the carrier returned success.

## 5. Prove the exact claim

```console
one test --root AcmeShipmentProvider --scenario conformance
one plan --root FulfillmentWorker
one inspect plan:sha256:… --subject provider
```

Conformance covers schema mapping, authentication, deadlines, rate limits,
idempotency, response loss, outcome lookup, malformed replies, disclosure, and
removal. Planning records why this exact realization satisfies the root and why
other candidates do not.

See [providers and adapters](/one/platform/providers) and
[communication](/one/model/communication).
