Blog

Capability-first API Reusability: Turning Old API Investment Into New Experiences

Kin Lane ·May 21, 2026
Table of contents

I have been walking through the Naftiko Framework use cases one at a time, and this is the one I have been quietly saving for last. Capability-first API reusability. The reason I saved it is that it is not really a separate use case. It is the underlying story behind every other use case in the list.

Every enterprise I walk into has more API investment than they have institutional memory for. REST services from three platform rewrites ago. SOAP endpoints that still move more revenue than anything modern. An Avro stream from the fraud team. A Protobuf-speaking gRPC service that the mobile team built in 2019 and does not want to be on-call for. A CSV export from a mainframe that somebody quietly turned into an internal “API” by dropping it behind nginx.

None of that is broken. None of it is going away. And it is all sitting there, waiting to be reused.

The honest shape of the problem

The AI conversation in most of these companies right now sounds like a rewrite pitch. “We should build a new API layer for the agents.” “Let’s stand up a modern service in front of the mainframe.” “We need an orchestration tier.”

I understand where it comes from. The existing API surface is messy. Some of it is SOAP. Some of it returns XML. Some of it returns CSV with no headers. None of it looks like the tidy MCP-shaped world the agent framework docs are selling.

But the second you pitch “rewrite,” you have lost. You have turned a three-month integration into a three-year program. You have asked the team that still runs the SOAP service to justify their existence. You have handed the platform review board a ticking clock they will use to slow everything down.

The capability-first reuse pattern says something different. Start from what you already have. Declare the consumed API as-is, with its actual auth, its actual payload formats, its actual quirks. Then add adapters on top, one at a time, as new experiences need them.

Start from consumed, grow from there

The shape of a Naftiko capability in this use case starts with a single consumes block that describes an existing API honestly.

naftiko: "1.0.0-alpha1"

info:
  title: Policyholder Records
  description: "Legacy policyholder lookup exposed as reusable capability"

binds:
  - name: POLICY_API_TOKEN
    type: vault
    path: "secret/data/policy/api"
    key: token
  - name: POLICY_CLIENT_CERT
    type: file
    path: "/run/secrets/policy-client.pem"

capability:
  consumes:
    - namespace: policy
      type: http
      baseUri: "https://policy.internal.example.com/svc"
      authentication:
        type: bearer
        token: "{{POLICY_API_TOKEN}}"
      headers:
        - name: X-Client-Cert
          value: "{{POLICY_CLIENT_CERT}}"
      resources:
        - name: policyholder
          path: "/policyholders/{policy_id}"
          operations:
            - name: get-policyholder
              method: GET
              responseFormat: xml
              inputParameters:
                - name: policy_id
                  in: path
                  type: string
                  required: true

That is the raw material. A SOAP-era endpoint that returns XML, protected by a vault-held token and a file-held client certificate. Nothing has been rewritten. Nothing has been replaced. The binds block pulls the token from the vault and the cert from the filesystem — both externalized, neither hardcoded. SCREAMING_SNAKE_CASE variable expressions let the values land in the right places without anything secret sitting in the YAML itself.

The second half of the capability — the exposes block — is where reuse actually happens.

  exposes:
    - type: rest
      basePath: "/api/policyholders"
      endpoints:
        - method: GET
          path: "/{policy_id}"
          description: "Look up a policyholder"
          call: policy.get-policyholder
          outputParameters:
            - type: object
              properties:
                - name: policyId
                  type: string
                  mapping: "$.Policyholder.Id"
                - name: fullName
                  type: string
                  mapping: "$.Policyholder.Name"
                - name: issuedOn
                  type: string
                  mapping: "$.Policyholder.IssuedOn"

    - type: mcp
      namespace: policyholder
      tools:
        - name: get-policyholder
          description: "Look up a policyholder by id"
          hints:
            readOnly: true
            idempotent: true
          call: policy.get-policyholder
          inputParameters:
            - name: policyId
              type: string
              required: true
              mapping: "pathParameters.policy_id"
          outputParameters:
            - type: object
              properties:
                - name: policyId
                  type: string
                  mapping: "$.Policyholder.Id"
                - name: fullName
                  type: string
                  mapping: "$.Policyholder.Name"

The upstream returns XML. The engine parses the XML, JSONPath maps it into a clean object, and serves the result on both a REST surface and an MCP surface. The SOAP service did not change. The vault did not change. The client certificate did not change. But the AI-facing tool and the modern REST endpoint are now both live, from one file.

This is what “capability-first reuse” looks like on the ground. The investment stays. The surface grows.

Reuse across capabilities, not just within one

The other half of this story is that a consumes declaration does not have to live inside a single capability. The framework supports consumes import and reuse across capabilities, with optional namespace aliasing. That means the same upstream policy API declared once can be referenced from a dozen capabilities — one for claims intake, one for agent support, one for the underwriting copilot, one for a partner portal — without each one re-declaring the auth, the certificate, the base URI, or the operation contracts.

Import by location. Alias the namespace if you need to. The capability that imports it reuses the declaration verbatim.

I care about this because it is the difference between “we have a capability library” and “we have five copies of the same integration floating around.” The import-by-location pattern is boring infrastructure and it is exactly the kind of boring infrastructure that keeps API programs from drifting back into sprawl.

Three-dimensional lens, last time

Technology. Format-aware parsing does a lot of work here. JSON, XML, YAML, CSV, TSV, PSV, Avro, Protobuf, HTML, and Markdown — the engine can normalize any of these into the declared output shape. The legacy service returning XML, the data-lake export in Avro, the partner feed in CSV, the scraped HTML table — they all land as the same typed JSON on the exposed surface. Request bodies go the other direction: JSON, XML, form URL encoded, multipart form, all declarable.

Business. Nothing gets rewritten to deliver the new AI experience. That is the business argument that actually lands with the people who control budgets. The existing systems stay, the existing teams stay, the existing audit trails stay. The capability layer is additive.

Politics. This is the part I care about most. The rewrite-everything pitch is usually a power play dressed up as modernization. It rewards the team doing the rewriting and punishes the team maintaining the existing service. Capability-first reuse removes the rewrite from the table. It says the legacy team’s work is load-bearing and the new AI surface is additive on top of it. That changes who is in the room and who gets credit.

Features that matter for this use case

Pulled from the framework wiki, these are the primitives that make capability-first reuse real:

  • Externalized secrets via binds — file, vault, GitHub secrets, Kubernetes secrets, runtime injection
  • SCREAMING_SNAKE_CASE variable expressions — so the spec can reference credentials without containing them
  • Consumes import and reuse across capabilities — with optional namespace aliasing
  • Format-aware response parsing — JSON, XML, YAML, CSV, TSV, PSV, Avro, Protobuf, HTML, Markdown normalized to JSON
  • Multiple request body formats — JSON, XML, form URL encoded, multipart form
  • Incremental adapter addition — REST, MCP, or Skill, added to an existing consumed API declaration one at a time
  • Skill server exposure — with agent-compatible metadata when you want to target agent runtimes specifically

Those are the pieces that let a capability grow outward from an existing API instead of replacing it.

Closing the nine

This is post nine of nine in the use case walk. AI integration. Rightsize AI context. Elevate an existing API. Elevate Google Sheets. Compose AI context. Rightsize microservices. Rightsize a monolith. Capability-first context engineering. And now capability-first reuse.

The thread through all of them is the same. Declarative capabilities. Consumes and exposes. Format-aware parsing. Externalized secrets. Polyglot exposure from one YAML. The use cases are different framings of the same underlying pattern, because the pattern is flexible enough to be framed a lot of different ways.

If you want the whole series in one place, it is on the use case guide in the framework wiki, and the engine and fleet are both on GitHub under naftiko/framework and naftiko/fleet. Everything else lives at naftiko.io.

I will keep walking the list — just in a different direction next.