Tutorials Search / Backend integrations / Call external APIs from your backend
πŸ“ Written ● Intermediate Updated 2026-06-02

How do I call ElevenLabs and other APIs from my backend?

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.

What you'll learn

Step 1 β€” store the key as a secret

Open 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.

Step 2 β€” call ElevenLabs in one line

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.

Step 3 β€” any other API with http-fetch

For 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).

Why the allow-list?

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.

Keep keys in secrets, not code: the whole point is that the key lives in the encrypted vault and only the backend reads it. Never paste a live key into your app's source, a prompt, or an environment that ships to the browser. If a key leaks, rotate it at the provider and update the secret.

What's next