Integrations
Integrate Secret Storage
A customer-facing secret API is planned and not available. What you can integrate today is the foundation it will be built on: provider connections whose API keys and webhook signing secrets are verified, stored in OpenBao, leased per request and rotated through a retirement ledger. This page covers those routes and how to prove the secret never comes back.
Not available yet — Secret Storage is a planned capability. It is not part of Paycux today and cannot be enabled from the console. What Paycux provides today.
Before you begin
- A member with the owner or admin role. Only those roles create, rotate, disable or enable a connection.
- A project and an environment. Secret paths are scoped to the workspace, project and environment, and a reference from another environment is refused.
- An API key from your own Stripe or Paddle account whose prefix matches the connection mode: sk_test_ or rk_test_ for test, sk_live_ or rk_live_ for live, pdl_sdbx_ for a Paddle sandbox.
- The webhook signing secret from the same account, if the provider has already shown it. It can be added later.
Install
There is nothing to install. Paycux is a plain HTTPS JSON API, so every example on this page uses curl. Console routes send the dashboard session cookie, end-user routes send the application's realm access token as a bearer credential, and agent routes send the short-lived agent token. The routes that exist today are listed on What exists today.
1# Console routes carry the dashboard session cookie set by sign-in2curl https://api.paycux.com/v1/auth/session \3 -H "Cookie: __Host-paycux_session=<session>"45# End-user routes carry the application's realm access token6curl https://api.paycux.com/v1/<end-user route> \7 -H "Authorization: Bearer <realm access token>"
Configure
Your own services never hold the provider key. They hold the address of the API and the scope they operate in; the key stays in OpenBao and is used only by Paycux routes.
1PAYCUX_API_BASE_URL=https://api.paycux.com2PAYCUX_PROJECT_ID=<project id>3PAYCUX_ENVIRONMENT_ID=<environment id>
Then, in the dashboard:
- 1Open the project, then the environment, then Connections. Create a connection with a name, the provider, the mode and the API key; add the webhook signing secret now or later.
- 2Watch the result. A key that fails the read-only verification stores nothing and the API answers 400 PROVIDER_REJECTED.
- 3Register the webhook path shown on the connection with your provider, then add or rotate the signing secret from the same page. The connection becomes active when the first signed event verifies.
- 4Use Rotate to replace a key or signing secret. The old version stays valid until the new one is verified and activated.
Implement
Everything below is a console-session call. Your application never makes these; they are operator actions, and they are the only way a provider secret enters Paycux.
Create a connection
The key prefix must match the mode. The environment and the name are checked first, then the plan's connection limit, then the key is verified with a read-only provider call. Only after that is anything written to OpenBao, and the database row keeps a path and a version, not the value.
1curl -X POST "https://api.paycux.com/v1/environments/<environment id>/provider-connections" \2 --cookie "__Host-paycux_session=<session cookie>" \3 -H "Content-Type: application/json" \4 -d '{5 "projectId": "<project id>",6 "name": "stripe-test",7 "provider": "stripe",8 "mode": "test",9 "apiKey": "<Stripe test secret or restricted key>",10 "webhookSecret": "<Stripe webhook signing secret>"11 }'1213# 201 Created14{15 "id": "<connection id>",16 "name": "stripe-test",17 "provider": "stripe",18 "mode": "test",19 "status": "pending_webhook_verification",20 "hasWebhookSecret": true,21 "createdAt": "2026-10-13T09:00:00.000Z",22 "updatedAt": "2026-10-13T09:00:00.000Z",23 "webhookPath": "/v1/provider-connections/<connection id>/webhooks/stripe"24}2526# 400 INVALID_SCOPE key prefix does not match the mode27# 400 PROVIDER_REJECTED the provider refused the key; nothing stored28# 402 PLAN_LIMIT_EXCEEDED the plan's connection limit is reached29# 503 SECRET_UNAVAILABLE the secret store refused; nothing stored
Attach the webhook signing secret
A connection created without a signing secret receives one through this call. The database records a recovery intent before OpenBao is written, so an interrupted request is cleaned up by the maintenance worker instead of leaving an orphaned version.
1curl -X POST "https://api.paycux.com/v1/environments/<environment id>/provider-connections/<connection id>/webhook-secret" \2 --cookie "__Host-paycux_session=<session cookie>" \3 -H "Content-Type: application/json" \4 -d '{ "projectId": "<project id>", "webhookSecret": "<Stripe webhook signing secret>" }'56# 200 OK: hasWebhookSecret is now true, the secret itself is not returned
Rotate a credential
Rotation writes the replacement as a new version, verifies it (a provider call for API keys, a format check for signing secrets), activates it through the retirement ledger and revokes the previous version. previousRetirement is complete when the old version was retired in the request and pending when the maintenance worker will finish it.
1curl -X POST "https://api.paycux.com/v1/environments/<environment id>/provider-connections/<connection id>/rotate" \2 --cookie "__Host-paycux_session=<session cookie>" \3 -H "Content-Type: application/json" \4 -d '{ "projectId": "<project id>", "purpose": "webhook_signing", "value": "<new signing secret>" }'56# 200 OK7{8 "id": "<connection id>",9 "name": "stripe-test",10 "provider": "stripe",11 "mode": "test",12 "status": "active",13 "hasWebhookSecret": true,14 "createdAt": "2026-10-13T09:00:00.000Z",15 "updatedAt": "2026-10-14T08:00:00.000Z",16 "rotated": { "purpose": "webhook_signing", "version": 2, "previousRetirement": "complete" }17}1819# purpose "api_key" verifies the new key with the provider first:20# 400 PROVIDER_REJECTED keeps the current version; 409 IDEMPOTENCY_CONFLICT means another rotation is in progress
List connections without secrets
Any member role can read the list. It carries status, mode and whether a signing secret is attached; it never carries a key, a path or a version.
1curl "https://api.paycux.com/v1/environments/<environment id>/provider-connections?projectId=<project id>" \2 --cookie "__Host-paycux_session=<session cookie>"34# 200 OK5{6 "items": [7 {8 "id": "<connection id>",9 "name": "stripe-test",10 "provider": "stripe",11 "mode": "test",12 "status": "active",13 "hasWebhookSecret": true,14 "createdAt": "2026-10-13T09:00:00.000Z",15 "updatedAt": "2026-10-14T08:00:00.000Z"16 }17 ]18}
Disable and enable
Disabling is idempotent and stops the connection counting against the plan. Enabling leases the stored key, verifies it with the provider again and only then sets the status back to active, so a key revoked at the provider while the connection was off cannot come back as working.
1curl -X POST "https://api.paycux.com/v1/environments/<environment id>/provider-connections/<connection id>/disable?projectId=<project id>" \2 --cookie "__Host-paycux_session=<session cookie>"3# 200 OK: status "disabled"45curl -X POST "https://api.paycux.com/v1/environments/<environment id>/provider-connections/<connection id>/enable?projectId=<project id>" \6 --cookie "__Host-paycux_session=<session cookie>"7# 200 OK: status "active" after the stored key verified8# 400 PROVIDER_REJECTED or 503 leave it disabled
Verify
Two things need proving: that nothing Paycux returns contains the value, and that a bad rotation leaves the working credential in place.
- 1Create a connection and read the response and the Connections page. Both show status, mode and hasWebhookSecret, and neither shows the key.
- 2List connections through the environment route and download the workspace export. Search both for the key; it is not there.
- 3Rotate the API key with a value the provider rejects and confirm 400 PROVIDER_REJECTED. The previous key still works and the connection status is unchanged.
- 4Rotate with a valid key and confirm rotated.version increased and previousRetirement is complete or pending. A pending retirement is finished by the maintenance worker.
- 5Disable the connection, then enable it. Enabling leases the stored key and verifies it with the provider before the status returns to active.
Reference
Request and response shapes for each of these live in the API reference. Paths are relative to https://api.paycux.com.
| Method | Path | What it does |
|---|---|---|
| POST | /v1/environments/:environmentId/provider-connections | Create a connection: verify the key, write it to OpenBao, persist references only (console session; owner or admin). |
| GET | /v1/environments/:environmentId/provider-connections | List connections with status and hasWebhookSecret, no secrets (console session; any role). Takes projectId. |
| POST | /v1/environments/:environmentId/provider-connections/:connectionId/webhook-secret | Attach a webhook signing secret to a connection created without one (console session; owner or admin). |
| POST | /v1/environments/:environmentId/provider-connections/:connectionId/rotate | Rotate the api_key or webhook_signing secret as a new verified version (console session; owner or admin). |
| POST | /v1/environments/:environmentId/provider-connections/:connectionId/disable | Disable a connection; idempotent (console session; owner or admin). Takes projectId. |
| POST | /v1/environments/:environmentId/provider-connections/:connectionId/enable | Lease and re-verify the stored key, then set the status to active (console session; owner or admin). Takes projectId. |
| GET | /v1/workspace/export | Download a bounded, secret-free JSON export of the workspace (console session; owner or admin). |