Test your SaltingIO Bridge in the Playground before your frontend calls it

Use the SaltingIO Playground to test Bridges, preview GJSON transformations, and catch the auth and origin errors that only show up in production.

SaltingIO Team August 19, 2026 6 min read Developer Tools
saltingioplaygroundapi testingbridgesgjsondebuggingcorsapi securityfrontenddeveloper tools
Test your SaltingIO Bridge in the Playground before your frontend calls it

A Bridge that works is invisible. Your frontend calls one UUID, the upstream key stays hidden, and the response comes back already reshaped. A Bridge that doesn't work is a different experience: the failure happens inside a proxy layer, the browser console shows a 4xx from api.salting.io, and the real cause sits one hop away from where you're looking. Was it the template variable? The origin allowlist? The upstream API itself?

The Playground exists to close that gap. It's a Postman-style tester built into the SaltingIO dashboard, and running every new Bridge through it before writing a single line of frontend code will save you most of the debugging you'd otherwise do in production.

What the Playground actually is

Open Playground from the dashboard nav (it sits between Secrets and Logs). The layout is three columns: your secrets on the left, a request builder in the middle, and the response on the right.

The request builder has a Single and a Batch mode. In Single mode you get a method dropdown, the read-only record URL with a copy button, and three tabs. The Params tab auto-populates one field for every {{template}} variable found in the Bridge's destination URL, so you never have to remember what placeholders you defined. The Headers tab accepts up to 20 custom headers. The Transformation tab holds GJSON selectors, up to 50 rows, and once a response has come back you can click fields in the response tree to build selectors instead of typing paths by hand. Choosing POST, PUT, or PATCH adds a JSON body textarea.

The response panel shows the status code, response time in milliseconds, headers, and the body as a collapsible, searchable JSON tree. For Credentials there's a Decrypt Base64 toggle, which matters more often than you'd expect.

Walking through a real Bridge test

Say you've created a Bridge pointing at OpenAI's chat completions endpoint, with the API key stored in a header and a {{model}} placeholder in the configuration. Select it in the Playground, and the Params tab already shows a model field. Fill in gpt-4o-mini, switch the method to POST, paste a minimal messages payload into the body, and hit Send.

You get a status badge and the full upstream response. Now the useful part: expand the JSON tree, click choices.0.message.content, and the Playground adds it as a transformation row. Send again and the response shrinks to just that field. What you've built interactively is the ?select= query param, and the equivalent production call looks like this:

curl -s -X POST \
  "https://api.salting.io/r/<bridge-uuid>?model=gpt-4o-mini&select={reply:choices.0.message.content}" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Explain CORS in one sentence"}]}'

The response is {"reply":"..."} and nothing else. No key in the request, no backend in the path, and a payload small enough that you're not shipping OpenAI's full completion object to every browser.

Batch mode works the same way for multi-call pages. Each row is a secret dropdown with its own Params and Transform buttons, and sending mirrors the real POST /batch endpoint: the response array comes back in the same order as the requests. If a landing page needs three upstream calls on load, you can rehearse the whole round trip here first.

The sample code and master prompt generators

Below the request builder, the Playground renders ready-to-copy cURL, JavaScript, and Python snippets for the selected record. That's convenient but expected. The less expected feature is the master prompt for AI tools: a generated block of text that embeds the endpoint URL and, after you've sent a real request, the actual JSON response body.

The point is context transfer. Paste that prompt into Claude, Cursor, or ChatGPT and the model knows your exact endpoint shape and a real response payload, so the integration code it writes tends to be right on the first try instead of hallucinating field names. The copy button stays disabled until a request has fired, because without a live response body the prompt would be half empty.

Common pitfalls

It works in the Playground but returns 401 in production. In the Playground you're authenticated as the record's owner, so a Private Credential decrypts without any extra header. Your deployed frontend doesn't get that courtesy. It must send the record's key in the X-API-Key header, and the failure looks like this: {"error":"Authentication required","message":"Please provide your token in the X-API-Key header to decrypt the content."}. Two things to know: it's X-API-Key, not Authorization: Bearer (Bearer tokens are dashboard JWTs and won't work on /r/ endpoints), and the key is displayed exactly once, on the success modal when you create the Credential. If you didn't copy it or hit the Download .txt button then, it's gone.

403 Origin not allowed, but only from localhost. The Playground runs inside the dashboard, so it won't trip an origin allowlist that's missing your dev origin. The first fetch from your Vite app at localhost:5173 then fails with {"error":"Origin not allowed","message":"Your origin is not authorized to access this endpoint."}. The fix is adding your dev origin to the Bridge's allowed origins, and the trap is forgetting the port or the protocol: http://localhost:5173 and http://localhost:3000 are different origins as far as the allowlist is concerned.

Template variables are case-sensitive, and the Playground hides that from you. The Params tab auto-populates fields with the exact placeholder names, so a Bridge configured with {{Model}} gets tested with a correctly cased Model param every time. Then someone hand-writes ?model= in the frontend, substitution silently doesn't happen, and the literal string {{Model}} goes upstream. The symptom is a confusing upstream error (often a 404 or a validation complaint about an unknown model) rather than anything from SaltingIO itself. If an upstream error makes no sense, check the casing of every query param against the stored URL first.

Make it part of the workflow

A reasonable rule: no Bridge UUID lands in frontend code until it has produced a green status in the Playground with the same method, params, and transformation the frontend will use. That single habit converts the three failures above from production incidents into thirty-second fixes, and the sample code tab means the working request travels into your codebase by copy, not by retyping. Read the docs for the full parameter and transformation reference.