ChatGPT custom GPTs
Run the Veefore relay, import its OpenAPI document into a custom GPT, and have every action the GPT takes go through Veefore.
ChatGPT custom actions can send only a fixed API key, and the Veefore gateway needs a signature from the agent's private key. The Veefore relay bridges the two. You run it; it holds the agent key, signs, and forwards each call. The private key never goes to ChatGPT.
The relay decides nothing. Policy, risk, approvals and the credential broker run at the gateway, and if the relay is down nothing goes through.
Do the shared setup first: an agent for the GPT, a tool, a policy, enforcement on.
#Step by step
Make a relay key
This is what ChatGPT sends to the relay. It is not a Veefore key.
bashopenssl rand -base64 32
Deploy the relay
The relay is integrations/veefore-relay in the Veefore repository: one file,
no dependencies, and a Dockerfile. Deploy it anywhere that serves HTTPS
(Railway, Fly, Render, Cloud Run) with these variables:
| Variable | Value |
|---|---|
VEEFORE_GATEWAY_URL |
https://gateway.veefore.com |
VEEFORE_AGENT_ID |
the agent's id, agt_… |
VEEFORE_AGENT_KEY_ID |
the agent's key id, key_… |
VEEFORE_AGENT_PRIVATE_KEY |
the agent's private key, as shown in the console |
RELAY_API_KEYS |
the relay key from step 1 (comma-separate several to rotate) |
RELAY_PUBLIC_URL |
the relay's own https address |
VEEFORE_RUNTIME_ID |
optional, the runtime id from step 3 |
On Railway: New → GitHub repo, root directory integrations/veefore-relay,
set the variables, and Generate domain. With Docker:
bashdocker build -t veefore-relay integrations/veefore-relay
docker run --env-file relay.env -p 8787:8787 veefore-relay
Check it: https://<relay>/health answers {"status":"ok"}.
Register the runtime
Integrations → ChatGPT and API platforms → Add, same agent. Optionally put
its id in VEEFORE_RUNTIME_ID and redeploy.
Add the action to your GPT
In ChatGPT: Explore GPTs → Create → Configure → Actions → Create new action.
- Import from URL:
https://<relay>/openapi.json. - Authentication → API key → Auth type: Bearer, paste the relay key.
- Set the Privacy policy URL your organization uses for GPTs.
Tell the GPT how to use it
Add to the GPT's Instructions:
textBefore doing anything for the user that changes something (sending, creating,
updating, deleting, paying), call authorizeAction with the tool and parameters.
If the result is ALLOW, call executeAction with the same tool, the same
parameters and the authorization_id. If executeAction returns done: false,
nothing happened: tell the user why, using its message. If it says a person
must approve, tell the user it is waiting for approval and do not retry until
they say it was approved, then call executeAction again with the approval_id.
Never claim an action happened unless executeAction returned done: true.
Try it and check it
In the GPT's preview, ask it to send a test email. Then check Actions in
the console: the call is there with via: chatgpt_relay. Ask for something
your policy blocks: the GPT says it was refused, and nothing reached the
provider.
#What the relay exposes
| Operation | Endpoint | Notes |
|---|---|---|
listTools |
GET /tools |
The agent's authorized tools. |
authorizeAction |
POST /authorize |
Dry run. ALLOW returns authorization_id, 120 s, single use. |
executeAction |
POST /execute |
done: true only when it happened. |
getAction |
GET /actions/{id} |
Outcome of one action. |
getApproval |
GET /approvals/{id} |
Approval status. |
/health and /openapi.json need no key; everything else does. Each relay key
is limited to 60 requests a minute by default (RELAY_RATE_LIMIT_PER_MINUTE).
Request and response bodies are never logged.
A retried call that presents the same authorization_id or approval_id is
sent with the same idempotency key, so ChatGPT retrying a request does not
send the email twice.
#Security notes
- Treat the relay host like a credential store: it holds the agent's private key. Use the platform's secret variables, not a file in the image.
- Rotate the relay key by adding the new one to
RELAY_API_KEYS, updating the GPT, then removing the old one. - If the agent key leaks, revoke or rotate it under Agents; the relay stops working until it gets the new key.
- ChatGPT's own browsing and connectors act outside Veefore. The runtime is Partial at best for that reason.
#Troubleshooting
| Symptom | Fix |
|---|---|
A valid relay API key is required |
The GPT's action authentication is missing or the key differs from RELAY_API_KEYS. |
Agent authentication failed |
Wrong agent id, key id or private key, or VEEFORE_GATEWAY_URL differs from the gateway's address. |
| The relay will not start | It prints the missing variable. Relay keys must be at least 24 characters. |
listTools is empty |
Authorize the agent on a tool. |
| ChatGPT says "error talking to connector" | The relay is not reachable over HTTPS, or RELAY_PUBLIC_URL in the OpenAPI document is wrong. |