curl --request POST \
--url https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"result": {
"clientId": "fin-8f2c1a9b-0000-4000-8000-000000000001-checkout-service",
"name": "checkout-service",
"secret": "new-generated-value-shown-exactly-once",
"status": "ACTIVE",
"createdAt": "2026-09-03T10:12:00Z",
"lastRotatedAt": "2026-09-11T08:44:19Z"
}
}{
"success": false,
"errors": [
{
"code": "unauthenticated",
"message": "Please authenticate to perform this action."
}
]
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}Rotate a credential's secret
Replace a credential’s secret. The old one stops working immediately.
curl --request POST \
--url https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.venlyfinance.com/v1/api-credentials/{clientId}/secret")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"result": {
"clientId": "fin-8f2c1a9b-0000-4000-8000-000000000001-checkout-service",
"name": "checkout-service",
"secret": "new-generated-value-shown-exactly-once",
"status": "ACTIVE",
"createdAt": "2026-09-03T10:12:00Z",
"lastRotatedAt": "2026-09-11T08:44:19Z"
}
}{
"success": false,
"errors": [
{
"code": "unauthenticated",
"message": "Please authenticate to perform this action."
}
]
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}{
"success": false,
"errors": [
{
"code": "invalid-request",
"message": "The request contains invalid parameters."
}
],
"result": {}
}manage:credentials — see Required scopes.
Generates a new secret and returns it in this response only. The previous secret stops working immediately, so rotate only when the new value can be deployed at once. Tokens already issued against the old secret remain valid until they expire.
Rotation is refused on a DISABLED credential — enable it first.
Errors
| HTTP | code | When |
|---|---|---|
404 | credential-not-found | unknown clientId, or one belonging to another company — indistinguishable by design |
409 | credential-disabled | the credential is disabled; no secret was generated |
503 | keycloak-unavailable | the identity provider was unreachable; retry |
Authorizations
OAuth2 client credentials flow. Token endpoints:
- Token URL
- https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
Headers
Which tenant the request is scoped to, among those your token grants. Omit it when the token grants exactly one tenant; it is required when the token grants more than one. A supplied value must exactly match a tenant the token grants.
Absent when required, blank, malformed, or naming a tenant the token does not grant — each gets
the same generic 403 forbidden, which reveals neither whether a tenant exists nor which ones
you may use. Send the header once: a repeated header is rejected the same way.
"3fa85f64-5717-4562-b3fc-2c963f66afa6"
Path Parameters
The credential's OAuth client_id
Response
Secret rotated. The new secret is present in this response only.
Indicates whether the request was successful
A credential together with its secret. Returned by create and rotate only. Record the
secret immediately: Finance does not store it, no endpoint returns it afterwards, and a lost
secret is replaced by rotating the credential rather than by reading it.
Show child attributes
Show child attributes
Was this page helpful?

