UC-014 — API Key Management
| Field | Value |
|---|---|
| ID | UC-014 |
| Goal | Create, inspect and revoke API Keys for your account |
| Channel | All |
| Complexity | Basic |
| Estimated time | 5 minutes |
| APIs involved | GET /api/partner-gateway/v1/authentication, GET /api/partner-gateway/v1/authentication/me, POST /api/partner-gateway/v1/authentication, DELETE /api/partner-gateway/v1/authentication/{id} |
Real-world scenarios
- Developer onboarding: The team lead creates a dedicated API Key for a new integration, scoped to only the operations that integration needs.
- Periodic key rotation: FinSecure rotates its API Keys every 90 days as required by internal security policy.
- Revoke a compromised key: A developer accidentally committed an API Key to a public repository and needs to revoke it immediately.
Management flow
The diagram shows the complete API Key lifecycle: scope check, creation, listing and revocation.
Prerequisites
- Active account on the Qlara platform
- At least one existing API Key to authenticate management calls
- The calling key must be authorized for the
AUTHENTICATIONoperation
Step 1 — Check what your current key can do
Before creating a key, inspect the one you are calling with. A new key can only be granted operations the calling key already holds, so this tells you the maximum scope available to you.
curl -X GET https://lora-api.agiletelecom.com/api/partner-gateway/v1/authentication/me \
-H "X-Api-Key: YOUR_API_KEY"
Response — Current key
{
"id": 1,
"companyId": 100,
"userId": 42,
"username": "api-user",
"trafficType": 0,
"operations": ["SMS", "RCS", "WHATSAPP"],
"creationDate": "2025-03-10 14:30:00.000+0100",
"lastUpdateDate": "2025-03-10 14:30:00.000+0100"
}
:::info The key is never sent in the URL
The key is read from the X-Api-Key header, so this endpoint takes no parameters and never
echoes the key value back. It replaces the removed GET /authentication/{value}, which took a
raw key in the URL.
:::
Step 2 — Create a new API Key
Call the creation endpoint to generate a new key.
curl -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/authentication \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"userId": 4618,
"trafficType": 0,
"operations": ["SMS", "RCS", "WHATSAPP"]
}'
| Field | Required | Description |
|---|---|---|
userId | Yes | ID of the user the key belongs to. Keys without a userId are orphan and cannot be deleted through this API. |
operations | Yes | Operations the key may perform. Must be a non-empty subset of the operations held by the calling key. |
trafficType | No | Traffic type identifier (0 = standard). Leave at 0 unless instructed otherwise. |
Allowed values for operations: CONTACTS, SOCIALS, INBOX, AUTOMATION, MEDIA,
MESSAGES, EMAIL, REPORT, CALENDAR, SUBSCRIPTION, AUTHENTICATION, RCS, WHATSAPP,
SMS, CAMPAIGNS, EXPORTS, WEBHOOKS.
Response — Key created
{
"id": 1,
"companyId": 100,
"apiKey": "ak_live_abc123def456",
"username": null,
"trafficType": 0,
"operations": ["SMS", "RCS", "WHATSAPP"],
"creationDate": "2025-03-10 14:30:00.000+0100"
}
:::warning Save the key immediately
The apiKey field is shown only at creation time. Copy it and store it in a secret manager
(e.g. Vault, AWS Secrets Manager). It cannot be retrieved again through any endpoint.
:::
:::note No username on creation
Keys created here are identified by their id and userId and carry no username, so username
in the response is always null. A username sent in the request body is ignored.
:::
Behind the scenes — Key generation and scoping
- Authorization: The gateway resolves the calling key and checks it is authorized for the
AUTHENTICATIONoperation. - Scope check: The requested
operationsare compared against the calling key's own operations. Anything beyond them is refused with403— a key cannot grant privileges it does not have. - Generation: A key string is generated and returned once, in this response only.
- Association: The key is linked to the company of the calling key and to the
userIdyou supplied.
Step 3 — List existing keys
Retrieve the API Keys associated with your account. Add the optional userId query parameter to
filter by owner.
curl -X GET https://lora-api.agiletelecom.com/api/partner-gateway/v1/authentication \
-H "X-Api-Key: YOUR_API_KEY"
Response — Key list
[
{
"id": 1,
"companyId": 100,
"userId": 4618,
"username": "api-user",
"trafficType": 0,
"operations": ["SMS", "RCS", "WHATSAPP"],
"creationDate": "2025-03-10 14:30:00.000+0100",
"lastUpdateDate": "2025-03-10 14:30:00.000+0100"
},
{
"id": 2,
"companyId": 100,
"userId": 5172,
"username": null,
"trafficType": 0,
"operations": ["CONTACTS", "CAMPAIGNS", "MESSAGES"],
"creationDate": "2026-01-15 09:00:00.000+0100",
"lastUpdateDate": "2026-01-15 09:00:00.000+0100"
}
]
The full key value is never returned by this endpoint — only its metadata.
Step 4 — Revoke a compromised key
Delete a key that should no longer be used. The key id goes in the path.
curl -X DELETE https://lora-api.agiletelecom.com/api/partner-gateway/v1/authentication/1 \
-H "X-Api-Key: YOUR_API_KEY"
Response — Key revoked
204 No Content — the response has no body. A key that does not exist returns 404.
Behind the scenes — What happens after revocation
- Immediate invalidation: The key is removed from the Key Store. Subsequent requests using it receive
401 Unauthorized. - No rollback: Deletion is irreversible. To restore access, create a new key.
- Orphan keys: A key stored without a
userIdcannot be deleted through this API — this is whyuserIdis required at creation.
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | GET /authentication/me | 200 OK with the calling key's operations |
| 2 | POST /authentication | 201 Created, full apiKey returned once |
| 3 | GET /authentication | 200 OK with the array of keys (no key values) |
| 4 | DELETE /authentication/{id} | 204 No Content |
Complete end-to-end example
Scenario FinSecure: quarterly key rotation.
BASE=https://lora-api.agiletelecom.com/api/partner-gateway/v1
# 1. Check the scope available to the calling key
curl -s -X GET "$BASE/authentication/me" \
-H "X-Api-Key: $CURRENT_KEY" | jq '.operations'
# 2. Create the new key, scoped to the same operations
NEW_KEY=$(curl -s -X POST "$BASE/authentication" \
-H "Content-Type: application/json" \
-H "X-Api-Key: $CURRENT_KEY" \
-d '{
"userId": 4618,
"trafficType": 0,
"operations": ["SMS", "RCS", "WHATSAPP"]
}' | jq -r '.apiKey')
echo "New key: $NEW_KEY"
# 3. Verify the new key works and inspect its scope
curl -s -X GET "$BASE/authentication/me" \
-H "X-Api-Key: $NEW_KEY" | jq '{id, operations}'
# 4. Revoke the old key by its id
curl -s -o /dev/null -w "%{http_code}\n" \
-X DELETE "$BASE/authentication/$OLD_KEY_ID" \
-H "X-Api-Key: $NEW_KEY"
Variants
Create a least-privilege key per integration
Scope each key to the smallest set of operations that covers its job:
# Sender-only key
curl -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/authentication \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{"userId": 4618, "operations": ["SMS"]}'
# Marketing automation key
curl -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/authentication \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{"userId": 4618, "operations": ["CONTACTS", "CAMPAIGNS", "MESSAGES"]}'
Common errors
400 Bad Request — Missing or empty operations
{
"status": "fail",
"data": {
"operations": "operations is required: a key with no operations cannot authenticate any request"
}
}
Solution: Send a non-empty operations array. A key with no operations cannot authenticate anything.
401 Unauthorized — Invalid key
{
"status": "fail",
"data": {
"authentication": "Invalid or missing API key"
}
}
Solution: Verify that the X-Api-Key header is present and that the key used to manage other keys is still active and authorized for the AUTHENTICATION operation.
403 Forbidden — Requested operations exceed your scope
{
"status": "fail",
"data": {
"operations": "Requested operations exceed the caller's own scope"
}
}
Solution: A key cannot grant privileges it does not have. Call GET /authentication/me to see what the calling key holds, then request a subset of those operations.
404 Not Found — Key does not exist
Solution: Check the id in the path against the list returned by GET /authentication. Keys stored without a userId cannot be deleted through this API.
Next steps
- UC-016 — Monitor Credit and Subscription: Check the status of your subscription and remaining credit
- UC-001 — Send Single SMS: Use your new key to send the first message
- Authentication Guide: Full details on API Key and Basic Auth