> ## Documentation Index
> Fetch the complete documentation index at: https://docs.venlyfinance.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rotate a credential's secret

> Replace a credential's secret. The old one stops working immediately.

**Requires scope:** `manage:credentials` — see [Required scopes](/getting-started/authentication#required-scopes-finance-api).

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 |


## OpenAPI

````yaml api-reference/Finance-API-Specs.yaml POST /api-credentials/{clientId}/secret
openapi: 3.1.0
info:
  title: Venly Finance API
  description: >
    REST API for the Venly Finance platform:

    - Party management (Individuals & Organisations)

    - Identity verification — hosted KYC/KYB links and Sumsub share-token
    forwarding

    - Account management with party association

    - Wallet balances & token allowances on supported chains

    - Virtual bank accounts for global pay-in (EUR SEPA, USD ACH/WIRE/RTP/SWIFT)

    - Fiat-to-crypto payment sessions (pay-in)

    - Bank pay-outs — beneficiary allow-listing, routes, and PULL/PUSH pay-outs

    - Account-to-account fiat & crypto transfers

    - EIP-2612 permits and allowances

    - Webhook registration for asynchronous event delivery


    ## Authentication


    All endpoints use OAuth2 client credentials. Obtain a token first, then
    include it in every request:


    **Step 1 — Get a token:**

    ```bash

    curl -X POST
    https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
    \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d "grant_type=client_credentials&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}"
    ```


    **Step 2 — Use the token:**

    ```

    Authorization: Bearer {access_token}

    ```


    Tokens expire after **5 minutes**. Implement refresh logic in your client.


    ## Selecting a tenant


    A token that grants more than one tenant must say which one each request is
    for, in the

    `x-tenant-id` header. With a single-tenant token, omit it. Any value you
    send must exactly match a

    tenant the token grants; a missing, malformed or foreign value is answered
    with a generic

    `403 forbidden` that reveals nothing about which tenants exist. Send the
    header at most once.


    ## Request correlation


    Every response — including `401` and `403` — carries an `X-Correlation-Id`
    header identifying the

    operation in our logs. Quote it in a support request. You may supply your
    own, as

    `X-Correlation-Id` or (as a fallback) `X-Request-Id`, matching
    `^[A-Za-z0-9_.:-]{1,64}$`. A value

    outside that shape is replaced with a generated one rather than rejected.
  version: 1.10.0
  contact:
    name: Venly Support
    email: support@venly.io
    url: https://docs.venlyfinance.com
  license:
    name: Proprietary
  x-logo:
    url: https://venlyfinance.com/logo.png
  x-security-contact: security@venly.io
servers:
  - url: https://api.venlyfinance.com/v1
    description: Production
  - url: https://api-staging.venlyfinance.com/v1
    description: Staging
security:
  - OAuth2: []
tags:
  - name: Parties
    description: Party management (Individuals & Organisations)
  - name: Accounts
    description: Account management, party-role associations
  - name: Wallets
    description: Blockchain wallet balances
  - name: Virtual Bank Accounts
    description: Virtual bank account payment references for global payments
  - name: Fiat-to-crypto Payment Sessions
    description: >-
      Hosted fiat-to-crypto pay-in sessions. **Coming soon** — not yet enabled;
      use a virtual bank account to receive fiat today.
  - name: Payout Bank Accounts
    description: Allow-listing beneficiary bank accounts as pay-out destinations
  - name: Payout Routes
    description: >-
      Account-scoped routes pairing a beneficiary bank account with a crypto
      deposit asset
  - name: Payouts
    description: Crypto-to-fiat pay-outs over a registered route
  - name: Transfers
    description: Fiat and crypto transfer operations between accounts
  - name: Permits
    description: EIP-712 permit signature management for token approvals
  - name: Supported Assets
    description: >-
      Discover which chains and assets your tenant can settle in, and whether an
      account can use them yet.
  - name: Allowances
    description: Token allowance management for wallets
  - name: Webhooks
    description: Webhook registration, delivery testing and delivery history
  - name: Pay-Ins
    description: >-
      The pay-in ledger — every fiat credit that settled (or failed to settle)
      into an account wallet
  - name: Billing
    description: The invoices Venly has issued to your company
  - name: API Credentials
    description: Self-service management of your company's OAuth client credentials
  - name: Company
    description: Your own company profile
paths:
  /api-credentials/{clientId}/secret:
    parameters:
      - $ref: '#/components/parameters/TenantId'
    post:
      tags:
        - API Credentials
      summary: Rotate a credential's secret
      description: >
        **Requires scope:** `manage:credentials`


        Replaces the credential's secret and returns the new one.


        The previous secret stops working **immediately** — rotate only when the
        new value can be

        deployed. Tokens already issued against the old secret remain valid
        until they expire.


        **The new `secret` appears in this response only** and, like the one
        from create, cannot be

        recovered by reading. `lastRotatedAt` is updated to the moment of
        rotation.


        Rotation is refused on a disabled credential: enable it first.
      operationId: rotateApiCredentialSecret
      parameters:
        - $ref: '#/components/parameters/ClientId'
      responses:
        '200':
          description: Secret rotated. The new `secret` is present in this response only.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SingleApiCredentialWithSecretResponse'
              example:
                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'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Forbidden — the token lacks `manage:credentials`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: >
            `credential-not-found`. A `clientId` belonging to another company
            answers exactly this — same

            status, same code, same message as one that does not exist anywhere.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            `credential-disabled` — the credential is disabled; no new secret
            was generated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: >-
            `keycloak-unavailable` — the identity provider could not be reached.
            Retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  parameters:
    TenantId:
      name: x-tenant-id
      in: header
      required: false
      description: >
        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.
      schema:
        type: string
        format: uuid
        example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
    ClientId:
      name: clientId
      in: path
      required: true
      description: The credential's OAuth `client_id`
      schema:
        type: string
      example: fin-8f2c1a9b-0000-4000-8000-000000000001-checkout-service
  schemas:
    SingleApiCredentialWithSecretResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            result:
              $ref: '#/components/schemas/ApiCredentialWithSecret'
    ErrorResponse:
      type: object
      description: Error response wrapper
      properties:
        success:
          type: boolean
          description: Always false for error responses
          example: false
        errors:
          type: array
          description: List of errors that occurred
          items:
            $ref: '#/components/schemas/ErrorBody'
        result:
          type: object
          nullable: true
          description: Null or omitted when success is false
    BaseResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Indicates whether the request was successful
    ApiCredentialWithSecret:
      type: object
      description: >
        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.
      required:
        - clientId
        - secret
        - status
      properties:
        clientId:
          type: string
          example: fin-8f2c1a9b-0000-4000-8000-000000000001-checkout-service
        name:
          type: string
          example: checkout-service
        secret:
          type: string
          description: >-
            The OAuth `client_secret`. Shown here only; it cannot be recovered
            by reading.
        status:
          $ref: '#/components/schemas/ApiCredentialStatus'
        createdAt:
          type: string
          format: date-time
          nullable: true
        lastRotatedAt:
          type: string
          format: date-time
          nullable: true
          description: Set on a rotation response; absent on a create response
    ErrorBody:
      type: object
      description: Individual error details
      properties:
        code:
          type: string
          description: Machine-readable error code
          example: invalid-request
        message:
          type: string
          description: Human-readable error message
          example: The request contains invalid parameters.
    ApiCredentialStatus:
      type: string
      description: >
        Lifecycle state of a credential. There is no deleted state: revocation
        is `DISABLED`, which is

        reversible and preserves the credential's identity, roles and history.
      enum:
        - ACTIVE
        - DISABLED
  responses:
    Unauthorized:
      description: Authentication required or failed (401)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            errors:
              - code: unauthenticated
                message: Please authenticate to perform this action.
  securitySchemes:
    OAuth2:
      type: oauth2
      description: >
        OAuth2 client credentials flow. Token endpoints:

        - Staging:
        https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token

        - Production:
        https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
      flows:
        clientCredentials:
          tokenUrl: >-
            https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token
          scopes: {}

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.