Skip to content

API Extensions

Partners may provide an OpenAPI 3 specificication that defines a set of API endpoints they wish to make available inside a platform.

An extension field x-marketplace-integration-handler is required at the top level, paths, or operations of the OpenAPI 3 specification. This field should point to a JavaScript module that exports a handler function. This handler will receive a partner integratoin object as its first argument and a request object as its second. The handler should resolve with a response object.

See src/api/typescript/ for the interfaces that define the partner integration object and the request and response objects.

Note: this specification may support additional languages in the future.

Manifest Example

The api field in the manifest can be used to specify an OpenAPI v3 document. Generally that's too large to embed directly into a JSON blob, so put it in an openapi.yaml file along with the API extension handlers in a separate directory and include that in your manifest:

{
    "api": "file:api/openapi.yaml"
}

That file itself would look something like this:

openapi: 3.1.0

info:
  title: Exampe
  version: v1
  # catchall handler, will used if no handler is defined for a path
  x-partner-marketplace-handler: api/catchall.js

paths:
  # this route uses the handler defined in the `info` section above
  /catchall/{example}:
    get:
      description: yell a greeting at a user
      operationId:
      parameters:
        - in: path
          name: example
          schema:
            type: string
          required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                type: object
                properties:
                  greeting:
                    type: string
          description: OK
  /greeting:
    # handler for this path as a whole, this will be invoked for _all_
    # accepted methods on this operation
    x-partner-marketplace-handler: api/greeting.js
    get:
      description: send a greeting to the userk
      operationId: greeing
      parameters:
        - in: query
          name: name
          schema:
            type: string
          required: true
          description: the name of the user to greet
      responses:
        "200":
          content:
            application/json:
              schema:
                type: object
                properties:
                  greeting:
                    type: string
          description: OK
  /yell:
    post:
      # handler for a specific method on an operation, this would
      # only be invoked with a `POST` request is made to `/yell`
      x-partner-marketplace-handler: api/yell.js
      description: yell a greeting at a user
      operationId: yell
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                type: object
                properties:
                  greeting:
                    type: string
          description: OK

Handler Examples

The x-partner-marketplace-handler field should point to a JavaScript file that exports a single function that looks something like this:

export default async function ({ usage, tenant, platform }, request) {
    await usage.track('skuhere', 123);

    console.log(platform.id); // the identifier of the platform, `alli` in this case

    // if secrets were set up in the manifest, they'll be at platform.secrets
    // as an object with secret name as the key.
    console.log(platform.secrets);

    console.log(requst.method)
    console.log(request.url);
    console.log(request.body);
    console.log(request.parameters);

    return {
        status: 200,
        body: {
            greeting: `Hello, ${request.parameters.name}!`
        }
        headers: {
            'Content-Type': ['application/json'],
        }
    };
}

Platform Object

The first argument passed to the handler is a platform object with tenant, usage, and secrets properties.

Tenant

This is the tenant with the marketplace platform (eg an Alli Client).

Tenants have a unique id (identifier) property that identifies them with Alli, as well as an extension_version that identifies the app version the tenant has installed, and configuration which is the user supplied configuration defined in the app's manifest. Configuration will be a JSON object with the keys corresponding to the configuration fields defined in the manifest.

Usage

This is an object with a single method track. Usage tracked here will be recorded by alli marketplace for consumption based billing.

The SKU name here should be from the app's manifest.

usage.track('skuNameFromManifestHere', 123);

Secrets

These are the secrets configured in the manifest. They'll be in secretName: value pairs. Be sure to coordinate with your Alli rep to get the real secret values to the Alli team!

Platform

This is extra metadata about Alli itself. Generally this will have an id field with the value alli and that's it.

Requests and Responses

Requests have method, url, and body properties. If the content type is JSON Alli will parse the body for you.

Additionally any parameters defined in the OpenAPI spec will be parsed out and made available at request.parameters. This is a list of object, each with in, name, and value properties. in will be one of path, query, or header.

Responses should include a status, body, and headers. If body is anything other than a string, it will be JSON encoded.

Alli Does Not Validate Request Bodies for Apps

Defining the schema in the OpenAPI document is recommended, but Alli will not validate that schema for an app.

Building Apps with API Extensions

Alli will not do any additional build processes for an app when it provisions API endpoints. This means that the app should do any build processes before pushing a version to its OCI repository. Do not send us typescript files, only plain JavaScript files that can be run on Node v22. Include a node_modules directory as well if applicable.

Bundling the API code and configuration into the OCI repository can be done via oras.

Assuming a file system layout like this:

manifest.json
api/
  openapi.yaml
  handler.js
oras push https://example.com/your-repository \
    --config manifest.json:application/vnd.alli-marketplace.manifest.v1+json \
    ./api/:application/vnd.alli-marketplace.api+tar