A branded API portal has two separate questions to answer: which services should customers discover, and which operations should a particular credential be allowed to call?
Treat those as separate acceptance tests. A screenshot of a tidy service catalog cannot establish the permissions of an API key.
Disclosure: this guide uses Ace Data Cloud's current white-label catalog and credential documentation. It is written by the Ace Data Cloud team. The examples below are test designs, not reported customer results.
Record the boundary each setting controls
In the current portal, service visibility and documentation visibility are configured separately. Hiding a service does not automatically hide its documentation. A saved detail link may still open even when its directory entry is hidden.
Credential restrictions require their own configuration and evidence:
| Setting or check | What it establishes | What to verify separately |
|---|---|---|
| Service catalog visibility | Which service entries appear in the catalog | The credential's permitted API operations |
| Documentation visibility | Which documentation entries or subtrees appear | Whether an existing direct link is accessible |
allowed_api_ids |
The configured API allowlist for that credential | An allowed request and an appropriately designed rejected request |
expired_at |
The configured expiry time | Behavior after expiry, where safely testable |
limited_amount |
The configured credential usage limit | The documented unit, current usage and enforcement behavior |
These settings do not create a separate customer database or billing system for each branded site. A customer's existing balance also does not disappear when a purchase button is hidden.
Check what an empty allowlist means
The current credential-creation documentation says that allowed_api_ids accepts API UUIDs and that an empty array is normalized to no restriction. It is therefore unsafe to use [] as shorthand for “deny every API.” The documented default also allows an unrestricted value.
A non-empty list should contain the actual API IDs you intend to allow. Obtain them through the documented API catalog for the relevant service. Do not substitute model names, route strings, display titles or an Application ID.
“No restriction” here describes this particular credential filter. It does not waive service acquisition requirements, available credits or the other conditions of a request.
If your application's policy requires every newly issued test credential to have an explicit allowlist, validate that policy before sending a creation request. This small offline guard rejects an empty or malformed list:
from uuid import UUID
def require_explicit_allowlist(api_ids):
if not isinstance(api_ids, list) or not api_ids:
raise ValueError("Provide a non-empty list of allowed API UUIDs")
normalized = []
for item in api_ids:
if not isinstance(item, str):
raise ValueError("Each API ID must be a UUID string")
normalized.append(str(UUID(item)))
return list(dict.fromkeys(normalized))
This function makes no network calls, creates no credential and does not inspect any key. It only validates the local input shape. A well-formed UUID can still name a nonexistent API, so the service must validate the IDs and enforce the resulting scope. The guard also does not protect requests made through another client; runtime authorization belongs on the server.
Run the guard locally
Paste the function above and this example into one Python file. The UUID is a synthetic parser fixture; the example does not establish whether a matching API exists.
synthetic_id = "00000000-0000-4000-8000-000000000001"
cases = [
("empty", []),
("malformed", ["not-a-uuid"]),
("duplicate", [synthetic_id, synthetic_id]),
]
for label, candidate in cases:
try:
checked = require_explicit_allowlist(candidate)
except ValueError:
print(f"{label}: rejected locally")
else:
print(f"{label}: {len(checked)} unique UUID(s)")
The output is:
empty: rejected locally
malformed: rejected locally
duplicate: 1 unique UUID(s)
The duplicate case confirms that the local guard retained one syntactically valid UUID. Server-side ID validation and permission checks remain separate steps. This example performs no network request and creates no credential.
Test one allowed operation and one excluded operation
Use an authorized test account and a dedicated test credential. Do not repurpose a customer's production key or assume that owning a branded site gives you permission to manage another account's credentials.
Before calling anything, record the intended API scope, expiry and usage limit. Confirm the current service documentation and the cost of any operation you plan to run. Use synthetic inputs or material you have permission to use.
Build a small matrix for the actual service:
| Case | Setup | Evidence to capture |
|---|---|---|
| Included API | Valid credential, explicitly included API, otherwise valid request | Actual response and associated usage or request record |
| Excluded API | Same test identity; API deliberately excluded from its allowlist | Actual rejection and the documented interpretation of that response |
| Expired credential | Dedicated short-lived test credential after its configured expiry | Rejection after expiry, or an explicit “not exercised” result |
| Catalog-only change | Change a test site's display setting while holding credential policy constant | Catalog behavior and credential behavior recorded as separate observations |
Keep unrelated inputs valid where the service permits it. If the excluded request also has malformed parameters, missing service access or an invalid key, its failure may not demonstrate that the API allowlist worked. Record the actual reason instead of labelling every error an authorization success.
Do not pre-fill the matrix with a universal error code. Read the service's documented response and preserve the observed status and sanitized message. Do not deliberately exhaust a budget just to prove a usage limit. Configuration review, a live test and an untested assumption are different evidence levels.
For an asynchronous operation, preserve the original task ID when one is returned. Check that task after a timeout before considering another paid submission.
Keep an acceptance record without keeping the secret
This template captures the useful evidence without asking for the credential value:
Site and service:
Test time and time zone:
Authorized test identity / role:
Credential label (not the secret):
Configured API IDs, expiry and usage limit:
Operation expected to be allowed:
Operation expected to be rejected:
Observed status and sanitized result for each case:
Non-secret request/task reference, if appropriate:
Evidence level: settings reviewed / live result / not exercised
Remaining uncertainty and next owner:
Test credential cleanup owner:
Remove authorization headers, cookies, full tokens, private inputs and access-bearing result URLs from shared evidence. Credential-management responses can themselves contain secrets, so avoid logging their complete bodies. Use the support-ticket redaction guide when preparing an attachment.
After testing, have the authorized owner retire credentials that are no longer needed, following the service's documented process. Verify the credential label and dependents before changing it. Keep the catalog result and the authorization result as separate conclusions in the handoff.
For this implementation, the catalog configuration guide describes the display controls, and the credential creation reference defines the accepted fields and their current semantics.
Top comments (0)