curl --request POST \
--url https://api.bachs.io/v1/customers/{customer_id}/portal-sessions \
--header 'Authorization: Bearer <token>'const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.bachs.io/v1/customers/{customer_id}/portal-sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.bachs.io/v1/customers/{customer_id}/portal-sessions"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.bachs.io/v1/customers/{customer_id}/portal-sessions"
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))
}{
"id": "psn_9f2c4a7b1d3e",
"url": "https://portal.bachs.io/s/6Yc0nQpR2vX1sK7fLbA9tE"
}{
"detail": "Invalid API key",
"error_code": "UNAUTHORIZED"
}{
"detail": "API key does not have permission for this operation",
"error_code": "FORBIDDEN"
}{
"detail": "Resource not found",
"error_code": "NOT_FOUND"
}{
"detail": "Rate limit exceeded. Please retry after a few seconds.",
"error_code": "TOO_MANY_REQUESTS"
}{
"detail": "An unexpected error occurred. Please try again later.",
"error_code": "INTERNAL_SERVER_ERROR"
}{
"detail": "The billing portal is not configured for this environment.",
"error_code": "SERVICE_UNAVAILABLE"
}Create a customer portal session
Creates a pre-authenticated customer portal session and returns the URL that opens it. The URL carries the session credential, so redirect the customer to it and do not log or share it. Sessions are short-lived; create a fresh one each time a customer asks to manage their billing. Requires the customers:write scope.
curl --request POST \
--url https://api.bachs.io/v1/customers/{customer_id}/portal-sessions \
--header 'Authorization: Bearer <token>'const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.bachs.io/v1/customers/{customer_id}/portal-sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.bachs.io/v1/customers/{customer_id}/portal-sessions"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.bachs.io/v1/customers/{customer_id}/portal-sessions"
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))
}{
"id": "psn_9f2c4a7b1d3e",
"url": "https://portal.bachs.io/s/6Yc0nQpR2vX1sK7fLbA9tE"
}{
"detail": "Invalid API key",
"error_code": "UNAUTHORIZED"
}{
"detail": "API key does not have permission for this operation",
"error_code": "FORBIDDEN"
}{
"detail": "Resource not found",
"error_code": "NOT_FOUND"
}{
"detail": "Rate limit exceeded. Please retry after a few seconds.",
"error_code": "TOO_MANY_REQUESTS"
}{
"detail": "An unexpected error occurred. Please try again later.",
"error_code": "INTERNAL_SERVER_ERROR"
}{
"detail": "The billing portal is not configured for this environment.",
"error_code": "SERVICE_UNAVAILABLE"
}Authorizations
Bearer token authentication. Pass your API key as Authorization: Bearer sk_.... See Authentication for keys, scopes, and sandbox vs production.
Path Parameters
Response
Success
The session identifier, prefixed with psn_. Use it to correlate a session with your own logs; it is not a credential and cannot be exchanged for access.
"psn_9f2c4a7b1d3e"
The URL that opens the portal as this customer. It carries the session credential, so it works on any device and must not be logged or shared.
"https://portal.bachs.io/s/6Yc0nQpR2vX1sK7fLbA9tE"

