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 type | Injected as |
|---|---|
bearer_token | Authorization: Bearer <token> (or any format containing {token}) |
header_key | A configured header, e.g. X-API-Key: <key> |
basic_auth | Authorization: Basic <token> — store the base64-encoded username:password pair as the credential value |
aws_sig_v4 | AWS Signature V4 signing — intended for AWS-compatible APIs; see the AWS reference |
The injection contract
Section titled “The injection contract”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
headeror aquery_param, names itskey, and takes its value fromtoken(the primary credential) oradditional_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"}]Walkthrough
Section titled “Walkthrough”1. Store the credential
Section titled “1. Store the credential”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:
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"}]2. Set the allowed hosts
Section titled “2. Set the allowed hosts”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):
alter managed-secrets set-allowed-hosts <secret-id> --host billing.internal.example.com3. Verify the credential
Section titled “3. Verify the credential”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.
4. Issue a grant and call the API
Section titled “4. Issue a grant and call the API”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, osfrom 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.
Policies on custom APIs
Section titled “Policies on custom APIs”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.
Differences from catalog templates
Section titled “Differences from catalog templates”Everything else — storage, grants, delegation, rotation, audit, request-shape policy rules — is identical. The differences:
| Catalog template | Custom template | |
|---|---|---|
| Injection contract | Provider-verified | Operator-configured |
| Allowed hosts | Often derived from the provider | Operator-configured (required for proxied calls) |
| Save-time credential verification | Where the provider supports it | Always skipped — verified on first use |
| Content rules (operations / parameters / redaction) | Where the provider has an operation catalog | Not available |