TL;DR: In the backend console (lingcode.dev/backends β Settings β Secrets & integrations) add your key, e.g. ELEVENLABS_API_KEY. Then call it from your app with client.functions.invoke('elevenlabs-tts', { text }) β the key never leaves the server. For any other service, allow-list its domain under Allowed fetch hosts and use client.functions.invoke('http-fetch', { url, headers }), referencing secrets as {{MY_KEY}}.
The dangerous way to use a third-party API from a web app is the obvious one: put the key in your frontend code. Now it's in every visitor's browser. The right pattern is to keep the key on a server and call the service from there β but standing up "a server" just to hide a key is exactly the friction LingCode Cloud removes. Your managed backend already is that server, so it can hold the secret and make the call for you.
This builds on a connected managed backend. Two pieces make external calls safe: an encrypted secret store (where the key lives, server-side, never sent to the browser) and function templates that run on the backend and make the outbound request with that key injected.
http-fetch functionOpen lingcode.dev/backends (signed in with the same account as your IDE), pick your backend, and go to Settings β Secrets & integrations. Add a secret with an UPPER_SNAKE name and paste the value β for ElevenLabs that's ELEVENLABS_API_KEY. It's encrypted at rest (AES-256-GCM) and the console only ever shows you the key names afterward, never the values. Nothing about this secret is reachable from your app's code or network β only backend functions can read it.
There's a vetted elevenlabs-tts function built in. From your app (using the LingCode SDK the agent already wires up):
const { data } = await client.functions.invoke('elevenlabs-tts', {
text: 'Hello from LingCode Cloud',
// voice_id and model_id are optional
});
// data.audio_base64 is MP3 audio you can play:
new Audio('data:audio/mpeg;base64,' + data.audio_base64).play();
The function runs on the backend, reads ELEVENLABS_API_KEY from the vault, calls ElevenLabs, and returns the audio. Your frontend never sees the key. If you ask the agent ("add a button that reads this text aloud with ElevenLabs"), it knows this template exists and writes exactly this call.
http-fetchFor a service without a dedicated template, use the generic http-fetch β but first allow-list its domain under Settings β Allowed fetch hosts (e.g. api.openai.com). Then:
const { data } = await client.functions.invoke('http-fetch', {
url: 'https://api.openai.com/v1/responses',
method: 'POST',
headers: { Authorization: 'Bearer {{OPENAI_API_KEY}}', 'content-type': 'application/json' },
body: { model: 'gpt-4o-mini', input: 'Say hi' },
});
The {{OPENAI_API_KEY}} token is replaced server-side with the secret you stored β it's never in the request your app makes. data carries the response status, headers, and body (parsed JSON when applicable).
http-fetch runs inside LingCode's network, so an unrestricted "fetch any URL" would be a server-side request forgery (SSRF) hole β a way to poke internal services. The allow-list is the guard: only domains you explicitly add are reachable, and the request is additionally blocked from resolving to any private/internal address. Empty allow-list = no outbound calls. Dedicated templates like elevenlabs-tts are pre-vetted to a fixed host, so they don't need the allow-list.