Skip to content

SaaS subscription stack (WorkOS + Datadog on AWS)

Source: examples/saas-subscription-api.yaml

To check and price this model from a clone of the repository:

infra-cost-model validate examples/saas-subscription-api.yaml
infra-cost-model compute --time-basis monthly examples/saas-subscription-api.yaml
# Example: SaaS subscription stack (WorkOS + Datadog on AWS)
# Demonstrates: SaaS vendors priced from vendor price rows
# (infra_cost_model/vendors/workos and infra_cost_model/vendors/datadog) next
# to AWS resources, with fixed monthly counts on non-IaC nodes.
#
# Issues: https://github.com/elecnix/infra-cost-model/issues/241,
# https://github.com/elecnix/infra-cost-model/issues/246

version: "1.0"

# The WorkOS and Datadog price rows ship with engine 0.3.0. An older engine
# prices these nodes differently or not at all, so the model states the
# version it needs and the engine refuses rather than reporting a number it
# cannot stand behind.
requiresEngine: ">=0.3.0"

workflow:
  name: saas-subscription-api
  entry: aws_apigatewayv2_api.public_api
  frequency:
    unit: perMinute
    value: 500

nodes:
  aws_apigatewayv2_api.public_api:
    nodeType: routing
    resourceAddress: aws_apigatewayv2_api.public_api
    provider: aws
    service: AmazonAPIGatewayHTTP
    region: us-east-1
    usageMetrics:
      requests: { unit: requests, value: 1 }

  # An HTTP API has no egress price of its own. AWS bills the response bytes
  # as data transfer out to the internet.
  data_transfer.public_api_egress:
    nodeType: external
    resourceAddress: data_transfer.public_api_egress
    provider: aws
    service: AWSDataTransfer
    region: us-east-1
    usageMetrics:
      internetOutGb: { unit: GB, value: 0.00002 }   # 20KB per request

  aws_lambda_function.api:
    nodeType: compute
    resourceAddress: aws_lambda_function.api
    provider: aws
    service: AWSLambda
    region: us-east-1
    usageMetrics:
      invocations: { unit: requests, value: 1 }
      avgDurationMs: { unit: ms, value: 200 }
      memoryMb: { unit: MB, value: 256 }

  # WorkOS: identity, priced per user, per connection and per feature. These
  # are counts, not traffic, so they carry `fixed: true` and their value is a
  # monthly total rather than a per-invocation multiplier. The price rows are
  # in infra_cost_model/vendors/workos/prices.yaml.
  workos_identity:
    nodeType: external
    resourceAddress: workos_identity
    provider: workos
    service: WorkOS
    region: global
    usageMetrics:
      # The first 1,000,000 monthly active users are free.
      AuthKit-MAU:    { unit: users,       value: 900000, fixed: true }
      # $125 a month for each of the first 15 SSO connections.
      SSO-Connection: { unit: connections, value: 2,      fixed: true }
      # $99 a month for a custom domain.
      Custom-Domain:  { unit: months,      value: 1,      fixed: true }

  # Datadog: Infrastructure Monitoring Enterprise, $23 per host a month billed
  # annually. The price rows are in infra_cost_model/vendors/datadog/prices.yaml.
  datadog_observability:
    nodeType: external
    resourceAddress: datadog_observability
    provider: datadog
    service: Infrastructure
    region: global
    usageMetrics:
      Infra-Enterprise-Host: { unit: hosts, value: 6, fixed: true }

  aws_dynamodb_table.tenants:
    nodeType: storage
    resourceAddress: aws_dynamodb_table.tenants
    provider: aws
    service: AmazonDynamoDB
    region: us-east-1
    usageMetrics:
      # This metric counts only the calls over read edges. The API only reads
      # tenants, so the table has no write edge and no write metric. A write
      # metric here would count no calls, and the engine would warn (#322).
      readRequests: { unit: requests, value: 1, edgeType: read }

edges:
  # Every response leaves AWS as data transfer out
  - from: aws_apigatewayv2_api.public_api
    to: data_transfer.public_api_egress
    rate: 1

  - from: aws_apigatewayv2_api.public_api
    to: aws_lambda_function.api
    rate: 1
  - from: aws_lambda_function.api
    to: aws_dynamodb_table.tenants
    rate: 1
    type: read