Skip to content

Guides

Connect a Custom API

Store a credential for any header-authenticated API — an internal service, a niche vendor, a self-hosted deployment — with the Custom managed-secret template.

Use a catalog template whenever one exists — it ships a verified injection contract, save-time credential verification, and (for many providers) an operation catalog that content rules can bind to. For everything else — an internal platform service, a regional SaaS vendor, a self-hosted deployment — the Custom template stores the credential with the same vault storage, grants, rotation, audit trail, and policy enforcement; the operator supplies the injection contract the catalog would otherwise provide.

Credential typeInjected as
bearer_tokenAuthorization: Bearer <token> (or any format containing {token})
header_keyA configured header, e.g. X-API-Key: <key>
basic_authAuthorization: Basic <token> — store the base64-encoded username:password pair as the credential value
aws_sig_v4AWS Signature V4 signing — intended for AWS-compatible APIs; see the AWS reference

Three settings define how the credential reaches the API:

  • Injection header — the header name the credential is written into (default Authorization). Security-critical and hop-by-hop headers (Host, Cookie, Content-Type, X-Forwarded-For, …) are rejected.
  • Injection format — the header value template. It must contain the {token} placeholder, which is replaced with the stored credential: Bearer {token}, Token {token}, or just {token}.
  • Additional injection rules — up to 10 extra injections for APIs that need more than one value per request, or that authenticate via query parameter. Each rule targets a header or a query_param, names its key, and takes its value from token (the primary credential) or additional_credentials.<field> (a named secondary credential, stored in the vault alongside the primary value and equally write-only):
[
{"target": "header", "key": "X-App-Key", "value_source": "additional_credentials.app_key"},
{"target": "query_param", "key": "api_key", "value_source": "token"}
]

Dashboard

Open the app, go to Managed Secrets → New secret, and pick the Custom card. Name the secret after the API (the name generates the slug), choose the Credential Type, set the Injection Header and Injection Format, add any Additional Injection Rules, list the Allowed Hosts, paste the credential, and click Store.

CLI

Omit --template to create a custom secret. This example stores an API key for an internal billing service that authenticates with X-Api-Key and requires a workspace id on every call:

Terminal window
printf '%s' "$BILLING_API_KEY" | alter managed-secrets create \
--name "Internal Billing API" \
--credential-type header_key \
--injection-header X-Api-Key \
--injection-format '{token}' \
--injection-rule @./injection-rules.json \
--credential-field workspace_id=ws_12345 \
--credential-value -

where injection-rules.json contains:

[{"target": "header", "key": "X-Workspace-Id", "value_source": "additional_credentials.workspace_id"}]

The host allowlist bounds where the credential can be sent — exact hosts (billing.internal.example.com) or leading-wildcard subdomains (*.example.com).

The dashboard’s create form includes the Allowed Hosts field. The CLI sets it as a follow-up step (or in one call via an --input JSON body carrying allowed_hosts):

Terminal window
alter managed-secrets set-allowed-hosts <secret-id> --host billing.internal.example.com

Save-time credential verification (preflight) needs a known provider endpoint to probe, so it is always reported as skipped for custom secrets. Confirm the credential works with a cheap test call before relying on it.

From here a custom secret behaves exactly like any catalog secret. Issue a grant binding it to a principal — system, user, group, or agent — then call the API with the SDK:

import asyncio, os
from alter_sdk import App, HttpMethod
async def main():
async with App(api_key=os.environ["ALTER_API_KEY"]) as app:
response = await app.request(
HttpMethod.GET,
"https://billing.internal.example.com/v1/invoices",
grant_id=os.environ["BILLING_GRANT_ID"],
)
print(response.status_code, response.json())
asyncio.run(main())
import { App, HttpMethod } from "@alter-ai/alter-sdk";
const app = new App({ apiKey: process.env.ALTER_API_KEY! });
try {
const response = await app.request(
HttpMethod.GET,
"https://billing.internal.example.com/v1/invoices",
{ grantId: process.env.BILLING_GRANT_ID! },
);
console.log(response.status, await response.json());
} finally {
await app.close();
}

Alter injects X-Api-Key: <key> and X-Workspace-Id: ws_12345 on the outgoing call. Grant issuance, per-user and group binding, rotation, and slug-based resolution all work as described in Provision secrets for backend services.

Every request-shape rule type works on a custom secret’s traffic, at every level: method/endpoint restrictions (“GET only”, “/v1/invoices/** only”), attribute match rules, IP allowlists, rate limits, time windows, human-in-the-loop approvals, and per-request rules from an SDK constrained client.

Content rules do not apply. Content rules bind operations and parameters from a reviewed operation catalog, which a custom API does not have — and they are fail-closed, so an operation-scoped rule that reaches a custom secret’s traffic denies it rather than ignoring it. Use method/endpoint restrictions to express “which calls are allowed” on a custom API.

Everything else — storage, grants, delegation, rotation, audit, request-shape policy rules — is identical. The differences:

Catalog templateCustom template
Injection contractProvider-verifiedOperator-configured
Allowed hostsOften derived from the providerOperator-configured (required for proxied calls)
Save-time credential verificationWhere the provider supports itAlways skipped — verified on first use
Content rules (operations / parameters / redaction)Where the provider has an operation catalogNot available

Report an issue with this page

Necessary

Required for sign-in, security, authorization, and remembering your choices.

Always active

Analytics

Helps us understand which product and documentation features are useful.

Performance diagnostics

Uses performance tracing and privacy-masked session replay to diagnose problems.

You can change these choices at any time from Cookie settings.