DEV Community

Cover image for How to Use AWS Lambda API for Serverless in 2026
Wanda
Wanda

Posted on • Originally published at apidog.com

How to Use AWS Lambda API for Serverless in 2026

TL;DR

The AWS Lambda API enables you to deploy, manage, and invoke serverless functions programmatically. It uses IAM authentication, RESTful endpoints for function management, and supports both async and sync invocation. This how-to guide covers authentication, function deployment, invocation patterns, event source mapping, and production serverless automation strategies.

Try Apidog today

Introduction

AWS Lambda processes trillions of requests monthly for over 1 million active users. For developers building serverless systems, automating Lambda API integration is essential for infrastructure as code, CI/CD, and large-scale event-driven apps.

Manual management of 50+ Lambda functions can waste 10-15 hours a week. API-driven integration automates deployments, supports blue-green releases, and enables dynamic scaling.

This guide gives you actionable steps for Lambda API integration: IAM setup, function deployment, invocation (sync/async), event source mapping, layered architecture, and production deployment. Follow along to automate your serverless pipeline.

What Is the AWS Lambda API?

AWS Lambda exposes a RESTful API for managing serverless functions. Capabilities include:

  • Function create/update/delete
  • Code deployment/versioning
  • Sync/async invocation
  • Event source mapping (SQS, Kinesis, DynamoDB, S3)
  • Layer management for shared code
  • Alias/routing config
  • Concurrency management
  • Logging and monitoring

Key Features

Feature Description
RESTful API Standard HTTPS endpoints
IAM Authentication AWS Signature Version 4
Async Invocation Fire-and-forget event processing
Sync Invocation Request-response pattern
Event Sources 200+ AWS service integrations
Layers Shared code and dependencies
Versions/Aliases Traffic shifting and rollbacks
Provisioned Concurrency Eliminate cold starts

Lambda Runtime Support

Runtime Versions Use Case
Node.js 18.x, 20.x API backends, event handling
Python 3.9, 3.10, 3.11 Data, ML
Java 11, 17, 21 Enterprise
Go 1.x High-perf APIs
Rust 1.x Low-latency
.NET 6, 8 Windows workloads
Ruby 3.x Web apps
Custom Any Container-based runtimes

API Architecture Overview

Lambda API endpoint format:

https://lambda.{region}.amazonaws.com/2015-03-31/
Enter fullscreen mode Exit fullscreen mode

API Versions

Version Status Use Case
2015-03-31 Current All Lambda operations
2018-01-31 Runtime Custom runtime interface

Getting Started: Authentication Setup

Step 1: Create AWS Account and IAM User

  1. Go to AWS Console
  2. Create an AWS account
  3. In IAM Console: Users → Create User
  4. Attach Lambda execution policies

Step 2: Generate IAM Credentials

Create programmatic access keys:

# AWS CLI
aws iam create-access-key --user-name lambda-deployer

# Output example
{
  "AccessKey": {
    "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
    "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  }
}
Enter fullscreen mode Exit fullscreen mode

Store credentials securely:

# ~/.aws/credentials
[lambda-deployer]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# Environment variables
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_DEFAULT_REGION="us-east-1"
Enter fullscreen mode Exit fullscreen mode

Step 3: Understand AWS Signature Version 4

All API requests require SigV4 signing. Example implementation:

const crypto = require('crypto');

class AWSSigner {
  constructor(accessKeyId, secretAccessKey, region, service = 'lambda') {
    this.accessKeyId = accessKeyId;
    this.secretAccessKey = secretAccessKey;
    this.region = region;
    this.service = service;
  }

  sign(request, body = null) {
    const now = new Date();
    const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
    const dateStamp = amzDate.slice(0, 8);

    // Canonical request
    const hashedPayload = body ? crypto.createHash('sha256').update(body).digest('hex') : 'UNSIGNED-PAYLOAD';
    const canonicalUri = request.path;
    const canonicalQuerystring = request.query || '';
    const canonicalHeaders = `host:${request.host}\nx-amz-date:${amzDate}\n`;
    const signedHeaders = 'host;x-amz-date';
    const canonicalRequest = `${request.method}\n${canonicalUri}\n${canonicalQuerystring}\n${canonicalHeaders}\n${signedHeaders}\n${hashedPayload}`;

    // String to sign
    const algorithm = 'AWS4-HMAC-SHA256';
    const credentialScope = `${dateStamp}/${this.region}/${this.service}/aws4_request`;
    const hash = crypto.createHash('sha256').update(canonicalRequest).digest('hex');
    const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${hash}`;

    // Calculate signature
    const kDate = this.hmac(`AWS4${this.secretAccessKey}`, dateStamp);
    const kRegion = this.hmac(kDate, this.region);
    const kService = this.hmac(kRegion, this.service);
    const kSigning = this.hmac(kService, 'aws4_request');
    const signature = this.hmac(kSigning, stringToSign, 'hex');

    // Authorization header
    const authorizationHeader = `${algorithm} Credential=${this.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;

    return {
      'Authorization': authorizationHeader,
      'X-Amz-Date': amzDate,
      'X-Amz-Content-Sha256': hashedPayload
    };
  }

  hmac(key, string, encoding = 'buffer') {
    return crypto.createHmac('sha256', key).update(string).digest(encoding);
  }
}

// Usage
const signer = new AWSSigner(
  process.env.AWS_ACCESS_KEY_ID,
  process.env.AWS_SECRET_ACCESS_KEY,
  'us-east-1'
);
Enter fullscreen mode Exit fullscreen mode

Step 4: Create Lambda API Client

const LAMBDA_BASE_URL = 'https://lambda.us-east-1.amazonaws.com/2015-03-31';

const lambdaRequest = async (path, options = {}) => {
  const url = new URL(`${LAMBDA_BASE_URL}${path}`);
  const method = options.method || 'GET';
  const body = options.body ? JSON.stringify(options.body) : null;

  const signer = new AWSSigner(
    process.env.AWS_ACCESS_KEY_ID,
    process.env.AWS_SECRET_ACCESS_KEY,
    'us-east-1'
  );

  const headers = signer.sign({ method, host: 'lambda.us-east-1.amazonaws.com', path }, body);

  const response = await fetch(url.toString(), {
    method,
    headers: {
      'Content-Type': 'application/json',
      ...headers,
      ...options.headers
    },
    body
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Lambda API Error: ${error.Message}`);
  }

  return response.json();
};

// Usage
const functions = await lambdaRequest('/functions');
console.log(`Found ${functions.Functions.length} functions`);
Enter fullscreen mode Exit fullscreen mode

Alternative: Use AWS SDK

AWS SDK handles SigV4 signing and retries:

const { LambdaClient, ListFunctionsCommand, CreateFunctionCommand, InvokeCommand } = require('@aws-sdk/client-lambda');

const lambda = new LambdaClient({ region: 'us-east-1' });

// List functions
const listCommand = new ListFunctionsCommand({});
const result = await lambda.send(listCommand);

// Create function
const createCommand = new CreateFunctionCommand({
  FunctionName: 'my-function',
  Runtime: 'nodejs20.x',
  Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
  Handler: 'index.handler',
  Code: {
    S3Bucket: 'my-bucket',
    S3Key: 'function.zip'
  }
});

const fn = await lambda.send(createCommand);
Enter fullscreen mode Exit fullscreen mode

Function Management

Creating a Function

Programmatically create a Lambda function:

const createFunction = async (functionConfig) => {
  const response = await lambdaRequest('/functions', {
    method: 'POST',
    body: {
      FunctionName: functionConfig.name,
      Runtime: functionConfig.runtime || 'nodejs20.x',
      Role: functionConfig.roleArn,
      Handler: functionConfig.handler || 'index.handler',
      Code: {
        S3Bucket: functionConfig.s3Bucket,
        S3Key: functionConfig.s3Key
      },
      Description: functionConfig.description || '',
      Timeout: functionConfig.timeout || 3,
      MemorySize: functionConfig.memorySize || 128,
      Environment: {
        Variables: functionConfig.environment || {}
      },
      Tags: functionConfig.tags || {}
    }
  });

  return response;
};

// Usage
const fn = await createFunction({
  name: 'order-processor',
  roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
  handler: 'index.handler',
  runtime: 'nodejs20.x',
  s3Bucket: 'my-deployments-bucket',
  s3Key: 'order-processor/v1.0.0.zip',
  description: 'Process orders from SQS queue',
  timeout: 30,
  memorySize: 512,
  environment: {
    DB_HOST: 'db.example.com',
    LOG_LEVEL: 'info'
  }
});

console.log(`Function created: ${fn.FunctionArn}`);
Enter fullscreen mode Exit fullscreen mode

Uploading Code Directly

Directly upload zipped function code (<50MB):

const fs = require('fs');
const path = require('path');

const createFunctionWithZip = async (functionName, zipPath) => {
  const zipBuffer = fs.readFileSync(zipPath);
  const base64Code = zipBuffer.toString('base64');

  const response = await lambdaRequest('/functions', {
    method: 'POST',
    body: {
      FunctionName: functionName,
      Runtime: 'nodejs20.x',
      Role: 'arn:aws:iam::123456789012:role/lambda-execution-role',
      Handler: 'index.handler',
      Code: {
        ZipFile: base64Code
      }
    }
  });

  return response;
};

// Package function
// zip -r function.zip index.js node_modules/
await createFunctionWithZip('my-function', './function.zip');
Enter fullscreen mode Exit fullscreen mode

Updating Function Code

Update code and optionally publish a new version:

const updateFunctionCode = async (functionName, updateConfig) => {
  const response = await lambdaRequest(`/functions/${functionName}/code`, {
    method: 'PUT',
    body: {
      S3Bucket: updateConfig.s3Bucket,
      S3Key: updateConfig.s3Key,
      Publish: updateConfig.publish || false
    }
  });

  return response;
};

// Usage
const updated = await updateFunctionCode('order-processor', {
  s3Bucket: 'my-deployments-bucket',
  s3Key: 'order-processor/v1.1.0.zip',
  publish: true // Create new version
});

console.log(`Updated to version: ${updated.Version}`);
Enter fullscreen mode Exit fullscreen mode

Updating Function Configuration

Change environment, memory, timeout, etc.:

const updateFunctionConfig = async (functionName, config) => {
  const response = await lambdaRequest(`/functions/${functionName}/configuration`, {
    method: 'PUT',
    body: {
      Runtime: config.runtime,
      Handler: config.handler,
      Description: config.description,
      Timeout: config.timeout,
      MemorySize: config.memorySize,
      Environment: {
        Variables: config.environment
      }
    }
  });

  return response;
};

// Usage
const updated = await updateFunctionConfig('order-processor', {
  timeout: 60,
  memorySize: 1024,
  environment: {
    DB_HOST: 'new-db.example.com',
    LOG_LEVEL: 'debug'
  }
});
Enter fullscreen mode Exit fullscreen mode

Deleting a Function

Remove a Lambda function:

const deleteFunction = async (functionName, qualifier = null) => {
  const path = qualifier
    ? `/functions/${functionName}?Qualifier=${qualifier}`
    : `/functions/${functionName}`;

  await lambdaRequest(path, { method: 'DELETE' });
  console.log(`Function ${functionName} deleted`);
};
Enter fullscreen mode Exit fullscreen mode

Function Invocation

Synchronous Invocation (Request-Response)

Invoke and wait for a result:

const invokeFunction = async (functionName, payload, qualifier = null) => {
  const path = qualifier
    ? `/functions/${functionName}/invocations?Qualifier=${qualifier}`
    : `/functions/${functionName}/invocations`;

  const response = await lambdaRequest(path, {
    method: 'POST',
    headers: {
      'X-Amz-Invocation-Type': 'RequestResponse', // Synchronous
      'X-Amz-Log-Type': 'Tail' // Include logs
    },
    body: payload
  });

  // Parse response
  const result = JSON.parse(Buffer.from(response.Payload).toString());
  const logs = Buffer.from(response.LogResult, 'base64').toString();

  return { result, logs };
};

// Usage
const { result, logs } = await invokeFunction('order-processor', {
  orderId: 'ORD-12345',
  customerId: 'CUST-67890',
  items: [
    { sku: 'PROD-001', quantity: 2 },
    { sku: 'PROD-002', quantity: 1 }
  ]
});

console.log(`Result: ${JSON.stringify(result)}`);
console.log(`Logs:\n${logs}`);
Enter fullscreen mode Exit fullscreen mode

Asynchronous Invocation (Fire-and-Forget)

Invoke function without waiting for completion:

const invokeAsync = async (functionName, payload) => {
  const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
    method: 'POST',
    headers: {
      'X-Amz-Invocation-Type': 'Event', // Asynchronous
      'X-Amz-Log-Type': 'None'
    },
    body: payload
  });

  return {
    statusCode: response.StatusCode,
    executionId: response['X-Amz-Execution-Id']
  };
};

// Usage - trigger async processing
const result = await invokeAsync('email-sender', {
  to: 'customer@example.com',
  template: 'order-confirmation',
  data: { orderId: 'ORD-12345' }
});

console.log(`Async invocation ID: ${result.executionId}`);
Enter fullscreen mode Exit fullscreen mode

Dry Run Invocation

Test permissions without executing the function:

const dryRunInvocation = async (functionName) => {
  const response = await lambdaRequest(`/functions/${functionName}/invocations`, {
    method: 'POST',
    headers: {
      'X-Amz-Invocation-Type': 'DryRun'
    }
  });

  return response;
};

// Usage - verify IAM permissions
try {
  await dryRunInvocation('order-processor');
  console.log('Invocation permissions OK');
} catch (error) {
  console.error('Permission denied:', error.message);
}
Enter fullscreen mode Exit fullscreen mode

Invocation Response Types

Invocation Type Behavior Use Case
RequestResponse Sync, wait for result API calls, CLI commands
Event Async, fire-and-forget Event processing, notifications
DryRun Test permissions only Validation, debugging

Version and Alias Management

Publishing Versions

Create an immutable snapshot of your function:

const publishVersion = async (functionName, description = null) => {
  const response = await lambdaRequest(`/functions/${functionName}/versions`, {
    method: 'POST',
    body: description ? { Description: description } : {}
  });

  return response;
};

// Usage
const version = await publishVersion('order-processor', 'v1.2.0 - Add tax calculation');
console.log(`Published version: ${version.Version}`);
Enter fullscreen mode Exit fullscreen mode

Creating Aliases

Point a named alias to a function version:

const createAlias = async (functionName, aliasName, version, description = null) => {
  const response = await lambdaRequest(`/functions/${functionName}/aliases`, {
    method: 'POST',
    body: {
      Name: aliasName,
      FunctionVersion: version,
      Description: description
    }
  });

  return response;
};

// Usage - Create production alias
const prodAlias = await createAlias('order-processor', 'prod', '5', 'Production version');
console.log(`Alias ARN: ${prodAlias.AliasArn}`);
Enter fullscreen mode Exit fullscreen mode

Traffic Shifting with Routing Config

Shift traffic between versions for safe deployments:

const updateAliasWithRouting = async (functionName, aliasName, routingConfig) => {
  const response = await lambdaRequest(`/functions/${functionName}/aliases/${aliasName}`, {
    method: 'PUT',
    body: {
      RoutingConfig: {
        AdditionalVersionWeights: routingConfig
      }
    }
  });

  return response;
};

// Usage - 10% traffic to version 6, 90% to version 5
await updateAliasWithRouting('order-processor', 'prod', {
  '6': 0.1
});

// After validation, shift to 100%
await updateAliasWithRouting('order-processor', 'prod', {});
Enter fullscreen mode Exit fullscreen mode

Alias Use Cases

Alias Version Purpose
dev $LATEST Development testing
staging Latest QA validation
prod Stable Production traffic
blue Current Blue-green deployment
green New Blue-green deployment

Event Source Mapping

Creating SQS Trigger

Connect an SQS queue to a Lambda function:

const createSQSEventSource = async (functionName, queueArn, batchSize = 10) => {
  const response = await lambdaRequest('/event-source-mappings', {
    method: 'POST',
    body: {
      EventSourceArn: queueArn,
      FunctionName: functionName,
      BatchSize: batchSize,
      Enabled: true
    }
  });

  return response;
};

// Usage
const mapping = await createSQSEventSource(
  'order-processor',
  'arn:aws:sqs:us-east-1:123456789012:orders-queue',
  10
);

console.log(`Event source created: ${mapping.UUID}`);
Enter fullscreen mode Exit fullscreen mode

Creating DynamoDB Stream Trigger

Connect DynamoDB Stream to Lambda:

const createDynamoDBEventSource = async (functionName, streamArn, startingPosition = 'LATEST') => {
  const response = await lambdaRequest('/event-source-mappings', {
    method: 'POST',
    body: {
      EventSourceArn: streamArn,
      FunctionName: functionName,
      StartingPosition: startingPosition,
      BatchSize: 100,
      BisectBatchOnFunctionError: true,
      MaximumRetryAttempts: 3
    }
  });

  return response;
};

// Usage
await createDynamoDBEventSource(
  'user-analytics',
  'arn:aws:dynamodb:us-east-1:123456789012:table/Users/stream/2026-03-25T00:00:00.000'
);
Enter fullscreen mode Exit fullscreen mode

Event Source Types

Source Use Case Batch Support
SQS Message queues Yes (1-10)
Kinesis Real-time streams Yes (1-10,000)
DynamoDB DB changes Yes (1-1,000)
S3 Object events No (1 per event)
EventBridge Event routing Yes
API Gateway HTTP APIs No
Schedule Cron jobs No

Layer Management

Creating a Layer

Package shared code/deps as a layer:

const createLayer = async (layerName, layerConfig) => {
  const response = await lambdaRequest('/layers', {
    method: 'POST',
    body: {
      LayerName: layerName,
      Description: layerConfig.description,
      CompatibleRuntimes: layerConfig.runtimes,
      Content: {
        S3Bucket: layerConfig.s3Bucket,
        S3Key: layerConfig.s3Key
      }
    }
  });

  return response;
};

// Usage
const layer = await createLayer('shared-utils', {
  description: 'Shared utilities and dependencies',
  runtimes: ['nodejs20.x', 'nodejs18.x'],
  s3Bucket: 'my-layers-bucket',
  s3Key: 'shared-utils/v1.zip'
});

console.log(`Layer ARN: ${layer.LayerArn}`);
Enter fullscreen mode Exit fullscreen mode

Using Layers in Functions

Attach layers to a Lambda function:

const createFunctionWithLayers = async (functionConfig) => {
  const response = await lambdaRequest('/functions', {
    method: 'POST',
    body: {
      FunctionName: functionConfig.name,
      Runtime: functionConfig.runtime,
      Role: functionConfig.roleArn,
      Handler: functionConfig.handler,
      Code: {
        S3Bucket: functionConfig.s3Bucket,
        S3Key: functionConfig.s3Key
      },
      Layers: functionConfig.layers // Array of layer ARNs
    }
  });

  return response;
};

// Usage
await createFunctionWithLayers({
  name: 'api-handler',
  roleArn: 'arn:aws:iam::123456789012:role/lambda-execution-role',
  handler: 'index.handler',
  runtime: 'nodejs20.x',
  s3Bucket: 'my-deployments-bucket',
  s3Key: 'api-handler/v1.0.0.zip',
  layers: [
    'arn:aws:lambda:us-east-1:123456789012:layer:shared-utils:1',
    'arn:aws:lambda:us-east-1:123456789012:layer:aws-sdk:3'
  ]
});
Enter fullscreen mode Exit fullscreen mode

Concurrency and Scaling

Setting Reserved Concurrency

Reserve execution capacity for a function:

const putFunctionConcurrency = async (functionName, reservedConcurrentExecutions) => {
  const response = await lambdaRequest(`/functions/${functionName}/concurrency`, {
    method: 'PUT',
    body: {
      ReservedConcurrentExecutions: reservedConcurrentExecutions
    }
  });

  return response;
};

// Usage - Reserve 100 concurrent executions
await putFunctionConcurrency('order-processor', 100);
Enter fullscreen mode Exit fullscreen mode

Account Concurrency Limits

Account Type Default Limit Increase Available
Free Tier 1,000 Yes
Pay-as-you-go 1,000 Yes
Enterprise 1,000+ Custom limits

Production Deployment Checklist

Before production deployment, ensure you:

  • [ ] Use AWS SDK for SigV4 signing
  • [ ] Implement versioning and aliases
  • [ ] Configure reserved concurrency for key functions
  • [ ] Set up dead letter queues (DLQ) for async invocations
  • [ ] Enable X-Ray tracing
  • [ ] Configure VPC for DB access
  • [ ] Use structured logging (JSON)
  • [ ] Set up CloudWatch alarms
  • [ ] Use layers for shared dependencies
  • [ ] Use blue-green deployment

Real-World Use Cases

API Backend

A SaaS company builds a serverless REST API:

  • Challenge: Variable traffic scaling
  • Solution: Lambda + API Gateway
  • Result: 99.99% uptime, 60% cost savings

Implementation:

  • One Lambda per resource
  • API Gateway for routing/auth
  • DynamoDB for data
  • Provisioned concurrency for low latency

Event Processing Pipeline

An e-commerce platform processes orders:

  • Challenge: Order spikes during sales
  • Solution: SQS + Lambda batch processing
  • Result: Zero lost orders, 10x spike handling

Implementation:

  • SQS queue for order buffer
  • Lambda processes 10 messages/batch
  • DLQ for failures
  • CloudWatch alerts for queue depth

Conclusion

The AWS Lambda API is a robust automation tool for serverless compute. Key implementation points:

  • IAM authentication with SigV4 (prefer AWS SDK)
  • Synchronous/asynchronous invocation
  • Version and alias management for release safety
  • Event source mapping for automation and integration
  • Layers for reusing code/dependencies
  • Apidog streamlines API testing and collaboration

FAQ Section

How do I authenticate with Lambda API?

Use AWS IAM credentials with Signature Version 4 signing. The AWS SDK automates this.

What is the difference between synchronous and asynchronous invocation?

Synchronous (RequestResponse) waits for function completion and returns a result. Asynchronous (Event) queues the request and returns immediately.

How do Lambda versions work?

Each published version is an immutable snapshot. Use aliases to point to versions and enable traffic shifting.

What are Lambda Layers?

Layers package code and dependencies separately from function code—enabling shared libraries across functions.

How do I reduce cold starts?

Use provisioned concurrency, small packages, and compiled languages (Go, Rust) for latency-critical workloads.

What is reserved concurrency?

Reserved concurrency guarantees execution slots for specific functions, preventing noisy neighbor issues.

Can I trigger Lambda from S3?

Yes, configure S3 event notifications to invoke Lambda on object events.

Top comments (0)