Integrations
Enable usage logs on AWS API Gateway
Stream Amazon API Gateway access logs to Apiable through Kinesis Firehose so Apiable can meter usage per plan and per subscription. This is what turns on usage-based billing and per-subscription analytics.
Usage logs are how Apiable sees what flows through your Amazon API Gateway. You deploy a Kinesis Firehose stream that ships your gateway's access logs to an S3 bucket, point the gateway stage at that stream, and paste a one-line JSON log format. Apiable then meters every call per plan and per subscription. This is the path that turns on usage-based billing and per-subscription analytics.
What do usage logs on AWS do for Apiable?
They give Apiable a per-request record of every API call. Apiable reads those records to attribute usage to the right plan and subscription, which is what usage-based billing and developer analytics run on.
A subscription on AWS already carries an API key and a rate limit. Usage logs add the missing piece: the actual call-by-call traffic, tagged with the plan and subscription it belongs to. Apiable ingests the delivered log files from your bucket and loads them so reports and metered billing can use them.
How do AWS access logs reach Apiable?
Through Amazon Kinesis Firehose. Your gateway stage writes access logs to a Firehose delivery stream, Firehose writes them to an S3 bucket, and Apiable ingests the files from that bucket.
The flow is:
- Your API Gateway stage emits one access log line per request.
- A Firehose delivery stream receives those lines and batches them.
- Firehose writes the batched files to an S3 bucket under the prefix
apiable/aws/logs/. - Apiable reads new files from that prefix, attributes each row to a plan and subscription, and loads them for billing and analytics.
How do you deploy the logs bucket and Firehose stream?
Run the two CDK scripts from the apiable/cdk repository against your AWS account: first the logs bucket, then the Firehose stream that targets it. Bootstrap CDK once first if this is a new account or region.
- Clone
apiable/cdkand install the AWS CDK toolkit. - Bootstrap CDK for your account and region, for example
./cdk-bootstrap.sh 123456789012 eu-central-1. - Deploy the S3 logs bucket. Skip this if you already have one.
- Deploy the Firehose stream, passing the bucket ARN from the previous step.
Deploy the S3 logs bucket
deploy-logs-bucket.sh takes your AWS account ID, region, and a stack name. The stack name becomes part of the bucket, so a stack name of dev produces a bucket named apiable-logs-dev.
./deploy-logs-bucket.sh 123456789012 eu-central-1 devThis creates the stack apiable-<stackname>-logs-bucket and a bucket whose ARN looks like arn:aws:s3:::apiable-logs-<stackname>. Note the bucket name, its ARN, and the region. You will pass the ARN to the next step and send all three to Apiable.
Deploy the Firehose stream
deploy-usagelogs-stream.sh takes your AWS account ID, region, the logs bucket ARN, and a stack name. It creates a Firehose delivery stream that writes to the bucket under the apiable/aws/logs/ prefix.
./deploy-usagelogs-stream.sh 123456789012 eu-central-1 arn:aws:s3:::apiable-logs-dev devThe stream is named amazon-apigateway-<name>. The name must start with amazon-apigateway-, which is an API Gateway requirement for access log destinations. The stream's ARN is written to cdk-outputs.json as the usagelogs-...-firehose-arn output. Copy that ARN. You paste it into the gateway stage in the next section.
How do you turn on access logging in the API Gateway console?
In the API Gateway console, open the stage, edit its Logs and Tracing settings, enable custom access logging, paste the Firehose ARN as the destination, and paste the one-line log format. Then save.
- Open the API Gateway console and select your API.
- Go to Stages and select the stage you want to meter.
- Open Logs and Tracing and choose to edit.
- Enable Custom access logging.
- In Access log destination ARN, paste the Firehose stream ARN from
cdk-outputs.json. - In Log Format, paste the one-line JSON format below.
- Save the changes.
What is the exact log format to paste?
Use this JSON object as a single line. The keys are fixed: Apiable reads them by name, and two of them, plan_id and subscription_id, come from the authorizer so each call can be attributed to the right plan and subscription.
{"api_id": "$context.apiId","api_key": "$context.identity.apiKey","key_id": "$context.identity.apiKeyId","ip": "$context.identity.sourceIp","method": "$context.httpMethod","uri": "$context.path","response_size": "$context.responseLength","response_status": "$context.status","resource_id": "$context.resourceId","request_id": "$context.requestId","request_latency": "$context.responseLatency","request_time": "$context.requestTimeEpoch","stage": "$context.stage","plan_id": "$context.authorizer.apiable_plan_id","subscription_id": "$context.authorizer.apiable_subscription_id"}| Key | Source | What it carries |
|---|---|---|
api_id | $context.apiId | The REST API the call hit. |
api_key | $context.identity.apiKey | The API key value on the request. |
key_id | $context.identity.apiKeyId | The API key ID, used to resolve the subscription. |
ip | $context.identity.sourceIp | The caller's source IP. |
method | $context.httpMethod | The HTTP method. |
uri | $context.path | The request path. |
response_size | $context.responseLength | The response size in bytes. |
response_status | $context.status | The HTTP status code. |
resource_id | $context.resourceId | The matched resource. |
request_id | $context.requestId | The unique request ID. |
request_latency | $context.responseLatency | The response latency. |
request_time | $context.requestTimeEpoch | The request time, epoch. |
stage | $context.stage | The stage that served the call. |
plan_id | $context.authorizer.apiable_plan_id | The Apiable plan, from the authorizer. |
subscription_id | $context.authorizer.apiable_subscription_id | The Apiable subscription, from the authorizer. |
When does usage start showing up?
After the stream is delivering and Apiable has wired up your bucket, usage appears once calls flow through the metered stage. Firehose batches before it writes, so allow a short delay between a call and the record landing.
The Firehose stream buffers records before writing to S3, so a single call is not delivered instantly. Once files land under apiable/aws/logs/, Apiable ingests them on its schedule and the usage becomes available to billing and analytics. Make a few test calls through the stage, then check developer analytics for the subscription.
Troubleshooting
Match what you see to the fix.
| What you see | What to do |
|---|---|
| No usage appears after enabling logging | Confirm the stage has Custom access logging enabled, the destination ARN is the Firehose stream, and the log format is pasted as one line. |
| The log format is rejected or logs look broken | The format must be a single line of valid JSON. Re-paste it with no line breaks, using the exact keys above. |
| Calls are logged but not attributed to a subscription | plan_id and subscription_id come from $context.authorizer.apiable_plan_id and apiable_subscription_id. Keep both keys in the format, and make sure the stage uses the Apiable authorizer. |
| The destination ARN will not accept your Firehose stream | The Firehose stream name must start with amazon-apigateway-. The Apiable CDK names it that way. If you created a stream by hand, rename it to match. |
| Files land in S3 but never get ingested | Send the region, bucket name, and bucket ARN to support@apiable.io so Apiable can connect ingestion to your bucket. |
| You changed billing but usage still does not bill | Usage logs feed metered billing. Confirm the Usage Events add-on is on for the plan and that the plan's matching criteria cover the calls you expect to bill. |