TL;DR
The AWS Lambda API lets you deploy, manage, and invoke serverless functions programmatically. It uses IAM authentication, RESTful endpoints for function management, synchronous and asynchronous invocation modes, and account-level concurrency limits. This guide covers authentication, deployment, invocation patterns, event source mappings, layers, and production deployment strategies.
Introduction
AWS Lambda processes trillions of requests monthly for over 1 million active users. If you build serverless applications, automation tools, or event-driven systems, Lambda API integration is essential for infrastructure as code and CI/CD pipelines.
Teams managing 50+ Lambda functions manually can lose 10–15 hours each week to deployments, configuration changes, and monitoring. Automating Lambda through its API helps you standardize deployments, implement blue-green releases, and adjust capacity as demand changes.
This guide shows how to:
- Authenticate with IAM and AWS Signature Version 4 (SigV4)
- Create, update, and delete functions
- Invoke functions synchronously and asynchronously
- Publish versions and route traffic with aliases
- Configure SQS and DynamoDB event source mappings
- Share dependencies through Lambda layers
- Set reserved concurrency for critical workloads
What Is the AWS Lambda API?
AWS Lambda exposes a RESTful API for managing serverless compute functions.
You can use it to:
- Create, update, and delete functions
- Deploy and version function code
- Invoke functions synchronously or asynchronously
- Configure event sources such as SQS, Kinesis, DynamoDB, and S3
- Publish and attach layers
- Manage aliases and weighted traffic routing
- Configure reserved concurrency
- Integrate logging and monitoring workflows
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 execution |
| Event sources | 200+ AWS service integrations |
| Layers | Shared code and dependencies |
| Versions and aliases | Traffic shifting and rollbacks |
| Provisioned concurrency | Reduce cold starts |
Lambda Runtime Support
| Runtime | Versions | Use case |
|---|---|---|
| Node.js | 18.x, 20.x | API backends, event processing |
| Python | 3.9, 3.10, 3.11 | Data processing, ML inference |
| Java | 11, 17, 21 | Enterprise applications |
| Go | 1.x | High-performance APIs |
| Rust | 1.x | Low-latency functions |
| .NET | 6, 8 | Windows workloads |
| Ruby | 3.x | Web applications |
| Custom | Any | Container-based runtimes |
API Architecture Overview
Lambda service endpoints follow this format:
https://lambda.{region}.amazonaws.com/2015-03-31/
For example, the Lambda endpoint in us-east-1 is:
https://lambda.us-east-1.amazonaws.com/2015-03-31/
API Versions
| Version | Status | Use case |
|---|---|---|
2015-03-31 |
Current | All Lambda operations |
2018-01-31 |
Runtime API | Custom runtime interface |
Getting Started: Authentication Setup
Step 1: Create an AWS Account and IAM User
Before calling the Lambda API:
- Create an AWS account.
- Open the IAM console.
- Go to Users → Create user.
- Attach the Lambda execution and deployment policies required by your workflow.
Use least-privilege IAM policies. A deployment identity usually needs permissions such as function creation, code updates, configuration updates, version publishing, alias management, and event source mapping management.
Step 2: Generate IAM Credentials
Create an access key for programmatic access:
aws iam create-access-key --user-name lambda-deployer
Example response:
{
"AccessKey": {
"AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
}
Store credentials securely.
Use an AWS credentials profile:
# ~/.aws/credentials
[lambda-deployer]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Or use environment variables:
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_DEFAULT_REGION="us-east-1"
Step 3: Understand AWS Signature Version 4
Every direct Lambda API request must be signed with SigV4.
The signing flow is:
- Create a canonical request.
- Create the string to sign.
- Derive a signing key and calculate the signature.
- Add the authorization headers.
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);
// 1. Create the 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,
canonicalUri,
canonicalQuerystring,
canonicalHeaders,
signedHeaders,
hashedPayload
].join('\n');
// 2. Create the string to sign.
const algorithm = 'AWS4-HMAC-SHA256';
const credentialScope = `${dateStamp}/${this.region}/${this.service}/aws4_request`;
const requestHash = crypto
.createHash('sha256')
.update(canonicalRequest)
.digest('hex');
const stringToSign = [
algorithm,
amzDate,
credentialScope,
requestHash
].join('\n');
// 3. Calculate the 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');
// 4. Add the authorization headers.
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, value, encoding = 'buffer') {
return crypto.createHmac('sha256', key).update(value).digest(encoding);
}
}
const signer = new AWSSigner(
process.env.AWS_ACCESS_KEY_ID,
process.env.AWS_SECRET_ACCESS_KEY,
'us-east-1'
);
For production workloads, prefer the AWS SDK. It handles SigV4 signing automatically and avoids maintaining custom signing code.
Step 4: Create a Lambda API Client
If you need to call the REST API directly, wrap requests in a reusable helper.
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();
};
// List deployed functions.
const functions = await lambdaRequest('/functions');
console.log(`Found ${functions.Functions.length} functions`);
Alternative: Use the AWS SDK
For production code, use AWS SDK for JavaScript v3.
npm install @aws-sdk/client-lambda
const {
LambdaClient,
ListFunctionsCommand,
CreateFunctionCommand,
InvokeCommand
} = require('@aws-sdk/client-lambda');
const lambda = new LambdaClient({
region: 'us-east-1'
});
// List functions.
const result = await lambda.send(new ListFunctionsCommand({}));
// Create a 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);
console.log(fn.FunctionArn);
Function Management
Create a Function
Create a Lambda function from a deployment artifact stored in S3.
const createFunction = async (functionConfig) => {
return 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 || {}
}
});
};
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}`);
Upload Code Directly
For small deployment packages under 50 MB when zipped, include the ZIP file directly in the API request.
const fs = require('fs');
const createFunctionWithZip = async (functionName, zipPath) => {
const zipBuffer = fs.readFileSync(zipPath);
const base64Code = zipBuffer.toString('base64');
return 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
}
}
});
};
Package your function first:
zip -r function.zip index.js node_modules/
Then create it:
await createFunctionWithZip('my-function', './function.zip');
Update Function Code
Deploy a new artifact and optionally publish an immutable version.
const updateFunctionCode = async (functionName, updateConfig) => {
return lambdaRequest(`/functions/${functionName}/code`, {
method: 'PUT',
body: {
S3Bucket: updateConfig.s3Bucket,
S3Key: updateConfig.s3Key,
Publish: updateConfig.publish || false
}
});
};
const updated = await updateFunctionCode('order-processor', {
s3Bucket: 'my-deployments-bucket',
s3Key: 'order-processor/v1.1.0.zip',
publish: true
});
console.log(`Updated to version: ${updated.Version}`);
Update Function Configuration
Use the configuration endpoint to modify runtime settings, memory, timeout, environment variables, and handler configuration.
const updateFunctionConfig = async (functionName, config) => {
return 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
}
}
});
};
await updateFunctionConfig('order-processor', {
timeout: 60,
memorySize: 1024,
environment: {
DB_HOST: 'new-db.example.com',
LOG_LEVEL: 'debug'
}
});
Delete a Function
Delete an entire function or a specific qualified version.
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`);
};
Function Invocation
Synchronous Invocation: Request-Response
Use RequestResponse when the caller needs the function result immediately, such as an API request or CLI command.
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',
'X-Amz-Log-Type': 'Tail'
},
body: payload
});
const result = JSON.parse(Buffer.from(response.Payload).toString());
const logs = Buffer.from(response.LogResult, 'base64').toString();
return { result, logs };
};
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}`);
Asynchronous Invocation: Fire-and-Forget
Use Event invocation for background work such as email delivery, notifications, or event processing.
const invokeAsync = async (functionName, payload) => {
const response = await lambdaRequest(
`/functions/${functionName}/invocations`,
{
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'Event',
'X-Amz-Log-Type': 'None'
},
body: payload
}
);
return {
statusCode: response.StatusCode,
executionId: response['X-Amz-Execution-Id']
};
};
const result = await invokeAsync('email-sender', {
to: 'customer@example.com',
template: 'order-confirmation',
data: {
orderId: 'ORD-12345'
}
});
console.log(`Async invocation ID: ${result.executionId}`);
Dry Run Invocation
Use DryRun to validate IAM permissions without running the function.
const dryRunInvocation = async (functionName) => {
return lambdaRequest(`/functions/${functionName}/invocations`, {
method: 'POST',
headers: {
'X-Amz-Invocation-Type': 'DryRun'
}
});
};
try {
await dryRunInvocation('order-processor');
console.log('Invocation permissions OK');
} catch (error) {
console.error('Permission denied:', error.message);
}
Invocation Response Types
| Invocation type | Behavior | Use case |
|---|---|---|
RequestResponse |
Synchronous; waits for the result | API calls, CLI commands |
Event |
Asynchronous; returns immediately | Notifications, background processing |
DryRun |
Validates permissions only | Validation, debugging |
Version and Alias Management
Publish a Version
A published Lambda version is an immutable snapshot of your function code and configuration.
const publishVersion = async (functionName, description = null) => {
return lambdaRequest(`/functions/${functionName}/versions`, {
method: 'POST',
body: description ? { Description: description } : {}
});
};
const version = await publishVersion(
'order-processor',
'v1.2.0 - Add tax calculation'
);
console.log(`Published version: ${version.Version}`);
Create an Alias
An alias is a named pointer to a specific Lambda version.
const createAlias = async (
functionName,
aliasName,
version,
description = null
) => {
return lambdaRequest(`/functions/${functionName}/aliases`, {
method: 'POST',
body: {
Name: aliasName,
FunctionVersion: version,
Description: description
}
});
};
const prodAlias = await createAlias(
'order-processor',
'prod',
'5',
'Production version'
);
console.log(`Alias ARN: ${prodAlias.AliasArn}`);
Shift Traffic with Alias Routing
Use weighted routing to direct a percentage of traffic to a new function version.
const updateAliasWithRouting = async (
functionName,
aliasName,
routingConfig
) => {
return lambdaRequest(
`/functions/${functionName}/aliases/${aliasName}`,
{
method: 'PUT',
body: {
RoutingConfig: {
AdditionalVersionWeights: routingConfig
}
}
}
);
};
// Route 10% of traffic to version 6.
await updateAliasWithRouting('order-processor', 'prod', {
'6': 0.1
});
// After validation, remove weighted routing.
await updateAliasWithRouting('order-processor', 'prod', {});
Common Alias Patterns
| Alias | Version | Purpose |
|---|---|---|
dev |
$LATEST |
Development testing |
staging |
Latest tested version | QA validation |
prod |
Stable version | Production traffic |
blue |
Current production version | Blue-green deployment |
green |
New version | Blue-green deployment |
Event Source Mapping
Event source mappings connect services that produce records—such as SQS, Kinesis, and DynamoDB Streams—to Lambda functions.
Create an SQS Trigger
const createSQSEventSource = async (
functionName,
queueArn,
batchSize = 10
) => {
return lambdaRequest('/event-source-mappings', {
method: 'POST',
body: {
EventSourceArn: queueArn,
FunctionName: functionName,
BatchSize: batchSize,
Enabled: true
}
});
};
const mapping = await createSQSEventSource(
'order-processor',
'arn:aws:sqs:us-east-1:123456789012:orders-queue',
10
);
console.log(`Event source created: ${mapping.UUID}`);
Create a DynamoDB Stream Trigger
const createDynamoDBEventSource = async (
functionName,
streamArn,
startingPosition = 'LATEST'
) => {
return lambdaRequest('/event-source-mappings', {
method: 'POST',
body: {
EventSourceArn: streamArn,
FunctionName: functionName,
StartingPosition: startingPosition,
BatchSize: 100,
BisectBatchOnFunctionError: true,
MaximumRetryAttempts: 3
}
});
};
await createDynamoDBEventSource(
'user-analytics',
'arn:aws:dynamodb:us-east-1:123456789012:table/Users/stream/2026-03-25T00:00:00.000'
);
Event Source Types
| Source | Use case | Batch support |
|---|---|---|
| SQS | Message queues | Yes, 1–10 |
| Kinesis | Real-time streams | Yes, 1–10,000 |
| DynamoDB Streams | Database changes | Yes, 1–1,000 |
| S3 | Object events | No, one event at a time |
| EventBridge | Event routing | Yes |
| API Gateway | HTTP APIs | No |
| Schedule | Cron jobs | No |
Layer Management
Layers package shared dependencies separately from function code. Use them to avoid duplicating common utilities across functions.
Create a Layer
const createLayer = async (layerName, layerConfig) => {
return lambdaRequest('/layers', {
method: 'POST',
body: {
LayerName: layerName,
Description: layerConfig.description,
CompatibleRuntimes: layerConfig.runtimes,
Content: {
S3Bucket: layerConfig.s3Bucket,
S3Key: layerConfig.s3Key
}
}
});
};
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}`);
Attach Layers to a Function
const createFunctionWithLayers = async (functionConfig) => {
return 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
}
});
};
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'
]
});
Concurrency and Scaling
Set Reserved Concurrency
Reserved concurrency allocates a number of concurrent execution slots to one function. Use it to protect critical workloads from account-level contention.
const putFunctionConcurrency = async (
functionName,
reservedConcurrentExecutions
) => {
return lambdaRequest(`/functions/${functionName}/concurrency`, {
method: 'PUT',
body: {
ReservedConcurrentExecutions: reservedConcurrentExecutions
}
});
};
await putFunctionConcurrency('order-processor', 100);
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 deploying a Lambda integration to production, verify the following:
- [ ] Use the AWS SDK for automatic SigV4 signing.
- [ ] Publish immutable versions for every release.
- [ ] Route production traffic through aliases.
- [ ] Configure reserved concurrency for critical functions.
- [ ] Set up dead-letter queues (DLQs) for asynchronous invocations.
- [ ] Enable X-Ray tracing for debugging.
- [ ] Configure VPC networking when functions need database access.
- [ ] Emit structured JSON logs.
- [ ] Create CloudWatch alarms for errors, throttles, and queue depth.
- [ ] Use layers for shared dependencies.
- [ ] Implement a blue-green deployment strategy.
Real-World Use Cases
API Backend
A SaaS company builds a serverless REST API.
- Challenge: Variable traffic and unpredictable scaling
- Solution: Lambda with API Gateway and automatic scaling
- Result: 99.99% uptime and 60% cost reduction compared with EC2
Implementation components:
- Lambda functions per resource
- API Gateway for routing and authentication
- DynamoDB for data storage
- Provisioned concurrency for consistent latency
Event Processing Pipeline
An e-commerce platform processes orders through an event-driven workflow.
- Challenge: Order spikes during sales events
- Solution: SQS with Lambda batch processing
- Result: Zero lost orders and 10x spike handling
Implementation components:
- An SQS queue buffers incoming orders.
- Lambda processes 10 messages per batch.
- A DLQ captures failed messages.
- CloudWatch alerts monitor queue depth.
Conclusion
The AWS Lambda API provides the building blocks for programmatic serverless deployments and operations.
Key takeaways:
- Authenticate with IAM and SigV4; prefer the AWS SDK for signing.
- Use synchronous invocations when callers need immediate results.
- Use asynchronous invocations for background event processing.
- Publish versions and use aliases for safer deployments and traffic shifting.
- Connect event sources to build event-driven systems.
- Use layers to share dependencies.
- Configure concurrency controls for critical workloads.
- Apidog streamlines API testing and team collaboration.
FAQ
How do I authenticate with the Lambda API?
Use AWS IAM credentials with Signature Version 4 signing. The AWS SDK handles signing automatically.
What is the difference between synchronous and asynchronous invocation?
Synchronous invocation (RequestResponse) waits for function completion and returns a result. Asynchronous invocation (Event) queues the request and returns immediately.
How do Lambda versions work?
Each published version is an immutable snapshot of a function. Use aliases to point to versions and shift traffic between releases.
What are Lambda Layers?
Layers package code and dependencies separately from function code, allowing multiple functions to reuse shared libraries.
How do I reduce cold starts?
Use provisioned concurrency, smaller deployment packages, and compiled languages such as Go or Rust for latency-critical functions.
What is reserved concurrency?
Reserved concurrency guarantees execution slots for a specific function and helps prevent noisy-neighbor issues.
Can I trigger Lambda from S3?
Yes. Configure S3 event notifications to invoke a Lambda function when objects are created or deleted.
Top comments (0)