> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clemta.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Attach a service to a company

> Orders a product against the company and bills you for it at creation, at your wholesale price. Idempotent - re-attaching the same product returns the existing order and does not bill you twice. Pass `Idempotency-Key` for safe retries.



## OpenAPI

````yaml /partner/openapi.yaml post /companies/{companyID}/service-orders
openapi: 3.1.0
info:
  title: Clemta Partner API
  description: |
    The Clemta partner surface. Authenticate with your API key as a bearer
    token (`Authorization: Bearer clmt_live_` or `clmt_test_`). Keys with
    the `clmt_test_` prefix operate in sandbox mode (`livemode: false`): test
    data never reaches fulfillment or billing.

    Versioning is date-based: pass `Clemta-Version` to pin a
    version, omit it to run on your account's pinned default. The effective
    version is echoed back on every response.
  version: '2026-08-13'
servers:
  - url: https://api.clemta.com/v1
    description: >
      Single host for both modes: `clmt_test_` keys operate in sandbox mode,
      `clmt_live_` keys in live mode.
security:
  - apiKey: []
tags:
  - name: Identity
    description: Identify the calling API key.
  - name: Accounts
    description: >-
      Create and read customer accounts - the incorporators companies are
      created under.
  - name: Companies
    description: Create and read client companies.
  - name: Service orders
    description: Order services against a company and follow their fulfilment.
  - name: Products
    description: The catalog you can offer, at your wholesale prices.
  - name: Tax filings
    description: >-
      Federal and state tax filings on your companies, opened by your client
      against the company's entitlements and worked by Clemta. Read-only. Follow
      them with the tax_filing.* events.
  - name: Files
    description: >-
      Documents Clemta publishes on your companies - formation deliverables,
      filed forms, letters. Read-only. Client KYC uploads are write-only and
      never listed.
  - name: Requirements
    description: >-
      Everything needed from you or your client - identity documents,
      service-order forms, Clemta's asks - as one resolvable resource. Fulfill
      over the API or hand your client a hosted link.
  - name: Status tracking
    description: >-
      End-customer status links - keyless, read-only access to a company's live
      status.
  - name: Events
    description: Poll the partner event stream.
  - name: Webhooks
    description: >-
      Events we deliver to your endpoint, and how to verify them. Each webhook
      below is a request WE send to you. Respond 2xx to acknowledge. Deliveries
      are signed and retried with exponential backoff over multiple days until
      acknowledged. Answer `410 Gone` to have the endpoint disabled and
      deliveries stopped. A `Retry-After` header on a `429` or `503` pushes the
      next attempt back. An endpoint that fails continuously for days is
      disabled automatically and the workspace owner is emailed - no events are
      lost, the stream stays available on `GET /v1/events`.


      ## Verifying a delivery


      Deliveries are signed per the [Standard
      Webhooks](https://www.standardwebhooks.com) specification, carrying BOTH
      schemes in one header: a symmetric `v1` HMAC (verify with your endpoint
      secret and any standardwebhooks library) and an asymmetric `v1a` ed25519
      signature (verify with the endpoint's public key, no shared secret held).
      Use whichever suits your setup.


      Every endpoint has its OWN signing secret (`whsec_...`), shown once when
      you create the endpoint. Each delivery carries three headers:


      - `Clemta-Webhook-Id` - the event id. Stable across retries: use it as an
      idempotency key so a redelivered event is processed once.

      - `Clemta-Webhook-Timestamp` - unix seconds of THIS attempt (a retry
      carries a fresh one).

      - `Clemta-Webhook-Signature` - a space-delimited list of `v1,<base64>`
      signatures. More than one while a secret rotation's overlap window is
      open, one per active secret.


      Each is also sent under its bare Standard Webhooks name (`webhook-id`,
      `webhook-timestamp`, `webhook-signature`) with the same value, which is
      what off-the-shelf standardwebhooks libraries look up.


      To verify by hand:


      1. Build the signed content by joining the id, the timestamp, and the raw
      request body with literal `.` separators: `{id}.{timestamp}.{body}`. Use
      the body exactly as received - do not re-serialize the JSON.

      2. Base64-decode your endpoint secret after the `whsec_` prefix. That is
      the HMAC key.

      3. Compute HMAC-SHA256 over the signed content, base64 encode it, and
      compare it against each `v1,` entry in constant time. Accept if any
      matches, otherwise reject.

      4. Check the timestamp is within 5 minutes of now, to reject replays.


      Because the secret is unique to your endpoint, a signature can only be
      verified by you - a delivery meant for another endpoint cannot be made to
      verify here. Keep the secret confidential. If it leaks, roll the
      endpoint's secret from the Webhooks page of your partner dashboard.
  - name: Sandbox
    description: >-
      Test-key-only endpoints for rehearsing event flows. Trigger a lifecycle
      transition on a test company and receive the matching webhook, without
      waiting for a real formation to progress.
paths:
  /companies/{companyID}/service-orders:
    post:
      tags:
        - Service orders
      summary: Attach a service to a company
      description: >-
        Orders a product against the company and bills you for it at creation,
        at your wholesale price. Idempotent - re-attaching the same product
        returns the existing order and does not bill you twice. Pass
        `Idempotency-Key` for safe retries.
      operationId: createServiceOrder
      parameters:
        - $ref: '#/components/parameters/CompanyId'
        - $ref: '#/components/parameters/ClemtaVersion'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateServiceOrderBody'
      responses:
        '201':
          description: The service order.
          headers:
            Clemta-Version:
              $ref: '#/components/headers/ClemtaVersion'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceOrder'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  parameters:
    CompanyId:
      name: companyID
      in: path
      required: true
      description: ID of the company.
      schema:
        type: string
        pattern: ^cmp_[0-9A-Za-z]{22}$
      example: cmp_0346sFPEvSkJvY8vt14NNw
    ClemtaVersion:
      name: Clemta-Version
      in: header
      required: false
      description: Date-based API version to run this request against.
      schema:
        type: string
        example: '2026-08-13'
  schemas:
    CreateServiceOrderBody:
      type: object
      description: >-
        Attach a product to a company. Idempotent - one order per product per
        company, unless the product's `repeat` policy allows more: then each
        instance (a tax year, a state, a bank, an owner, or simply the nth
        request) is its own order.
      required:
        - product_key
      properties:
        product_key:
          type: string
          minLength: 1
          maxLength: 50
          pattern: ^[a-z][a-z0-9_]{1,48}$
          description: >-
            The product to order, by key. Must be an active product in your
            catalog.
          example: ein
        options:
          type: object
          maxProperties: 10
          additionalProperties:
            type: string
            pattern: ^[a-z][a-z0-9_]{1,48}$
          description: >-
            Your choice for each of the product's `options` (key -> value), as
            listed on `GET /products`. A required option that is missing, an
            unknown key, or an unknown value answers `400 invalid_request` with
            one `errors[]` entry per problem.
          example:
            llc_members: multi_member
        shareholder:
          type: string
          pattern: ^sh_[0-9A-Za-z]{22}$
          description: >-
            The company owner this order is for. Required exactly when the
            product repeats per owner (`repeat: per_shareholder` - an ITIN
            application). Refused on every other product.
        form:
          type: array
          maxItems: 100
          description: >-
            Optionally answer the first form step in the same call - for
            services whose first step collects input (e.g. an EIN's SS-4 or an
            operating agreement's details), the order kicks off fully in one
            request.
          items:
            $ref: '#/components/schemas/ServiceFormField'
    ServiceOrder:
      type: object
      description: >-
        One product ordered on a company. Billed to you when created (or at each
        period end for arrears products). Reversed by a credit if cancelled
        before fulfilment starts. An active recurring order can be cancelled to
        stop renewing at the period end.
      required:
        - object
        - id
        - company
        - product_key
        - status
        - unit_amount
        - currency
        - created_at
      properties:
        object:
          type: string
          enum:
            - service_order
          description: Entity name.
        id:
          type: string
          pattern: ^so_[0-9A-Za-z]{22}$
          example: so_0346sFPEvSkJvY8vt14NNw
        company:
          type: string
          pattern: ^cmp_[0-9A-Za-z]{22}$
          description: The company this order is on.
        product_key:
          type: string
          example: ein
        interval:
          type: string
          enum:
            - one_time
            - monthly
            - yearly
          description: Billing cadence - one_time, or recurring monthly/yearly.
        status:
          type: string
          enum:
            - received
            - quote_pending
            - in_progress
            - requires_action
            - completed
            - canceled
          description: >-
            Fulfilment status, derived from where Clemta has the order:
            `received` until fulfilment starts (a cancellable state),
            `quote_pending` while a priced-by-quote product waits for the price
            and your acceptance (also cancellable - cancelling declines the
            quote), `in_progress` while Clemta works, `requires_action` while
            the current step waits on a form from you or your client (an open
            `form` requirement says which), `completed` once the final step is
            reached - terminal, `completed_at` is set and
            `service_order.completed` fires once - and `canceled`.
        options:
          type: object
          additionalProperties:
            type: string
          description: >-
            The variant choices this order was placed with (option key ->
            value).
          example:
            llc_members: multi_member
        form_required:
          type: boolean
          description: >-
            True when fulfilment needs a form from the client (e.g. an ITIN or
            BOI service). Known once the order reaches fulfilment.
        workflow_status:
          type: string
          description: >-
            The live fulfilment step (e.g. "Application In Progress", "Signature
            Request"). Present once the order is being fulfilled.
        form:
          allOf:
            - $ref: '#/components/schemas/ServiceOrderForm'
          description: >-
            The form the current step is waiting on, when `form_required` is
            true - the fields to submit next via the form endpoint. Present on
            the single-order view.
        unit_amount:
          type: integer
          format: int64
          description: >-
            The wholesale price you were billed, in the currency's smallest unit
            (cents).
          example: 7900
        currency:
          type: string
          example: usd
        created_at:
          type: string
          format: date-time
        quote:
          $ref: '#/components/schemas/ServiceOrderQuote'
        shareholder:
          type: string
          description: >-
            The company owner this order is for (products ordered per owner,
            e.g. an ITIN).
        outcome:
          type: string
          description: >-
            How a completed order ended, where completion alone does not say - a
            bank application's approved or declined, a good-standing check's not
            eligible. Recorded by Clemta. A decline is a delivered service, not
            a credit. Absent while the work runs and on orders whose completion
            is the whole answer.
        included_in:
          type: string
          description: >-
            Present when this order was attached by a bundle order (the
            formation's included services) - it names the bundle product.
            Included orders bill nothing of their own. A paid option choice
            bills only the difference.
        fees:
          type: array
          items:
            $ref: '#/components/schemas/OrderFee'
          description: >-
            Pass-through lines this order carried beside `unit_amount` - the
            state's own charge and the processing fee, frozen at their
            order-time amounts. Each appears as its own line on your statement.
        next_renewal_at:
          type: string
          format: date-time
          description: >-
            When the next period bills (for a product billed in arrears, the end
            of the running period). Only on recurring orders. Absent once
            renewals end.
        renewal_cancel_requested_at:
          type: string
          format: date-time
          description: >-
            When you requested cancellation. The request awaits a Clemta
            decision - renewals keep billing until it is approved. You hear the
            outcome as `service_order.renewal_canceled` or
            `service_order.renewal_cancel_denied`.
        renewal_canceled_at:
          type: string
          format: date-time
          description: >-
            When the cancellation was approved. The order stops billing at
            `renewal_ends_at`. Fulfilment status is unaffected.
        renewal_ends_at:
          type: string
          format: date-time
          description: >-
            The period end the service runs to after a renewal cancel. An
            arrears product still bills this period at that moment, then stops.
        canceled_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          description: >-
            When the order first reached `completed`. `service_order.completed`
            announces this moment, and it does not change afterward.
    ServiceFormField:
      type: object
      description: One answer to a service order's current form step.
      required:
        - value
      properties:
        key:
          type: string
          description: The field key from the form schema, when it has one.
        field_name:
          type: string
          description: The field's label from the form schema.
        value:
          description: >-
            The answer - a string, number, or boolean. A file field's value is a
            pre-uploaded file id (POST /v1/files, purpose additional_document).
    ServiceOrderForm:
      type: object
      description: The form the order's current fulfilment step is waiting on.
      required:
        - fields
      properties:
        title:
          type: string
        warning:
          type: string
          description: A caution to show above the form.
        fields:
          type: array
          items:
            $ref: '#/components/schemas/ServiceFormFieldDef'
    ServiceOrderQuote:
      type: object
      description: >-
        The negotiated-price lifecycle on a product priced per order (for
        example, catch-up bookkeeping). `pending` until Clemta reviews the work
        and sets the amount, `quoted` while the price waits for your
        `accept_quote`, `accepted` once you took it and the charge landed.
        Nothing is billed before acceptance.
      required:
        - state
      properties:
        state:
          type: string
          enum:
            - pending
            - quoted
            - accepted
        unit_amount:
          type: integer
          format: int64
          description: >-
            The Clemta-set wholesale price, in the currency's smallest unit.
            Absent while pending.
        currency:
          type: string
        quoted_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
          description: >-
            Accept before this moment. A lapsed quote refuses acceptance, and
            Clemta re-prices on request.
        accepted_at:
          type: string
          format: date-time
    OrderFee:
      type: object
      required:
        - kind
        - unit_amount
      description: >-
        One pass-through charge riding a service order, at the amount resolved
        when the order was made.
      properties:
        kind:
          type: string
          description: What the line is - state_fee, processing_fee or government_fee.
          example: state_fee
        unit_amount:
          type: integer
          format: int64
          description: The amount in the currency's smallest unit.
          example: 30000
        currency:
          type: string
          example: usd
    Error:
      type: object
      description: >-
        Error response: a stable machine-readable `code`, human-readable
        `title`/`detail`, and for validation failures an `errors` array naming
        every violating field.
      required:
        - type
        - title
        - status
        - code
      additionalProperties: false
      properties:
        type:
          type: string
          description: Link to the error reference entry for this code.
          example: https://docs.clemta.com/partner/errors#resource_already_exists
        title:
          type: string
          description: Short human summary of the error class.
        status:
          type: integer
          format: int32
          minimum: 100
          maximum: 599
          description: HTTP status code, also included in the body.
        code:
          type: string
          enum:
            - api_key_invalid
            - api_key_expired
            - insufficient_scope
            - ip_address_not_allowed
            - invalid_request
            - invalid_api_version
            - resource_missing
            - method_not_allowed
            - test_mode_only
            - resource_already_exists
            - idempotency_key_mismatch
            - idempotency_key_in_use
            - request_too_large
            - billing_account_inactive
            - entitlement_required
            - rate_limit
            - api_error
          description: Stable machine-readable code - branch on this, never on `detail`.
        detail:
          type: string
          description: Human-readable specifics of this occurrence, wording may change.
        request_id:
          type: string
          description: >-
            Identifier of this request. Quote it in a support request so we can
            trace the failure.
        errors:
          type: array
          description: 'Present on validation failures: one entry per violating field.'
          items:
            type: object
            required:
              - reason
            additionalProperties: false
            properties:
              reason:
                type: string
              location:
                type: string
                description: JSONPath of the failing field, e.g. `$.name`.
              validation_type:
                type: string
                description: Schema keyword that failed.
              how_to_fix:
                type: string
    ServiceFormFieldDef:
      type: object
      description: >-
        One field of a form. It carries every attribute you need to render the
        field in your own UI, and the server validates answers against the same
        definition.
      required:
        - field_name
        - field_type
      properties:
        key:
          type: string
          description: Stable field key - pass it back as the answer's `key`.
        field_name:
          type: string
          description: The field's label.
        field_type:
          type: string
          enum:
            - text
            - textarea
            - number
            - date
            - boolean
            - select
            - multi_select
            - file
            - email
            - phone
            - address
          description: >-
            What kind of answer the field takes. `select` takes one of
            `options`, `multi_select` a list of them, `date` an ISO date
            (YYYY-MM-DD), `file` a pre-uploaded file id (POST /v1/files, purpose
            additional_document).
        required:
          type: boolean
        options:
          type: array
          items:
            type: string
          description: Allowed values for select / multi_select.
        guidance:
          type: string
          description: Longer explanation of what is being asked.
        help:
          type: string
          description: Short helper text under the input.
        note:
          type: string
          description: A caution shown near the field.
        placeholder:
          type: string
        info_points:
          type: array
          items:
            type: string
        conditional:
          $ref: '#/components/schemas/FieldConditional'
        validation:
          $ref: '#/components/schemas/FieldValidation'
        file:
          $ref: '#/components/schemas/FieldFileRule'
    FieldConditional:
      type: object
      description: >-
        This field applies only while another field holds one of the listed
        values.
      required:
        - field
        - values
      properties:
        field:
          type: string
          description: Key of the controlling field.
        values:
          type: array
          items:
            type: string
          description: Any of these values on the controlling field switches this one on.
    FieldValidation:
      type: object
      description: >-
        Constraints an answer must satisfy beyond its type. The server enforces
        these. A violation answers `invalid_request` with the field named in
        `errors[]`.
      properties:
        pattern:
          type: string
          description: Regular expression a text answer must match.
        min_length:
          type: integer
        max_length:
          type: integer
        min:
          type: number
          description: Lower bound for a number.
        max:
          type: number
    FieldFileRule:
      type: object
      description: Constraints on a file field's upload.
      properties:
        accepted_types:
          type: array
          items:
            type: string
          description: >-
            Media types or extensions accepted (e.g. `application/pdf`, `jpg`).
            Absent means PDF, JPEG and PNG.
        max_size_bytes:
          type: integer
          format: int64
  headers:
    ClemtaVersion:
      description: The API version the request was executed against.
      schema:
        type: string
  responses:
    BadRequest:
      description: Malformed request (e.g. unknown `Clemta-Version`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing, invalid, revoked, or grace-expired API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The requested resource does not exist, or is not yours.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: >-
        The request conflicts with existing state, such as an external_id
        already in use or a duplicate resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Rate limit exceeded, retry after the `Retry-After` header.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >
        Your API key, e.g. `Authorization: Bearer clmt_test_`. Live keys use the
        `clmt_live_` prefix.

````