openapi: 3.1.1
info:
  title: Dinie API
  version: '2026-03-01'
  description: |
    Embedded credit API for Dinie partners. Enables customer registration,
    credit offer management, loan origination, and event delivery
    via webhooks.
  contact:
    name: Dinie API Support
    url: https://dinie.nexaedge.dev
    email: api@dinie.com.br
  license:
    name: Proprietary
  x-logo:
    url: /img/dinie-logo.svg
  x-dark-logo:
    url: /img/dinie-logo-dark.svg
servers:
  - url: https://api.dinie.com.br/v3
    description: Production
  - url: https://sandbox.api.dinie.com.br/v3
    description: Sandbox
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: >
      OAuth2 Client Credentials authentication and API key management.


      Each `client_id` / `client_secret` pair represents an access credential.

      Exchange the credentials for a JWT token via `POST /auth/token` and send
      the token

      as Bearer in all requests. The token expires in 1 hour.


      You can create multiple credentials for different environments and revoke
      them

      individually.
    x-displayName: Authentication
  - name: Customers
    description: >
      The **Customer** resource (`cust_`) represents a credit borrower on the
      platform.

      The lifecycle follows: registration → KYC document submission → review →
      activation.


      Two processes happen in parallel:

      - **Credit analysis** — starts automatically upon registration

      - **KYC verification** — the customer completes at their own pace


      ## Lifecycle


      ```

      pending_kyc → under_review → active

      ```


      | Status | Description | Next Step |

      |---|---|---|

      | `pending_kyc` | Registered, awaiting documents | Submit documents and
      biometrics |

      | `under_review` | Documents submitted, under review | Wait for
      `customer.active` webhook |

      | `active` | Approved and eligible for credit | Check credit offers |


      ## Example: Complete Registration


      ```ruby

      # 1. Register the customer

      customer = client.customers.create(
        cpf: "123.456.789-00",
        cnpj: "12.345.678/0001-90",
        name: "João Silva",
        email: "joao@example.com",
        phone: "+5511999999999",
        trading_name: "Loja do João",
        external_id: "partner-ref-123"
      )

      # customer.id => "cust_550e8400..."

      # customer.status => "pending_kyc"

      # customer.kyc => list of pending documents


      # 2. Submit each required document

      customer.kyc.each do |item|
        next unless item.status == "pending"
        client.customers.upload_document(customer.id,
          type: item.type,
          file: File.open("docs/#{item.type}.pdf")
        )
      end


      # 3. Start biometric capture

      session = client.customers.create_biometrics_session(customer.id)

      # Redirect the customer to session.session_url


      # 4. Wait for customer.active webhook

      # When received, the customer is ready for credit

      ```


      ## Registration Idempotency


      Creating a customer with the same CPF/CNPJ and `external_id` returns the
      existing customer

      (`200 OK`). This allows safely retrying the request in case of timeout or

      network failure. The `409 Conflict` error only occurs when the
      `external_id` differs.


      ## Search


      ```ruby

      # By CPF

      customers = client.customers.list(cpf: "123.456.789-00")


      # By partner ID

      customers = client.customers.list(external_id: "partner-ref-123")

      ```


      ## Webhooks


      | Event | When it fires |

      |---|---|

      | `customer.created` | Customer registered via API |

      | `customer.under_review` | Documents submitted, KYC review started |

      | `customer.kyc_updated` | KYC item status updated (approved, rejected,
      correction) |

      | `customer.active` | Customer approved — eligible for credit offers |
    x-displayName: Customers
  - name: Credit Offers
    description: >
      The **CreditOffer** resource (`co_`) represents a pre-approved credit
      offer

      for a customer. Offers are automatically generated by Dinie when a
      Customer

      reaches the `active` status. You are notified via the
      `credit_offer.available` webhook.


      ## Flow: Offer → Simulation → Loan


      ```

      CreditOffer (available) → Simulation → Loan

      ```


      1. **Check the offers** available for a customer

      2. **Simulate different scenarios** of amount and term

      3. **Create the loan** from the simulation chosen by the customer


      ## Example: Simulate a Loan


      ```ruby

      # 1. List available offers

      offers = client.customers.list_credit_offers("cust_abc123",
        status: "available"
      )

      offer = offers.data.first

      # offer.id => "co_550e8400..."

      # offer.approved_amount => "50000.00"

      # offer.min_amount => "5000.00"

      # offer.interest_rate => 2.5 (% per month)

      # offer.valid_until => "2026-04-01T00:00:00Z"


      # 2. Simulate with different amounts

      sim_25k = client.credit_offers.simulate(offer.id,
        requested_amount: "25000.00",
        installment_count: 6
      )


      sim_40k = client.credit_offers.simulate(offer.id,
        requested_amount: "40000.00",
        installment_count: 12
      )


      # 3. Present options to the customer

      puts sim_25k.installments_value  # "4550.00" per installment

      puts sim_25k.cet_percentage      # 35.2% per year

      puts sim_40k.installments_value  # "3800.00" per installment

      puts sim_40k.cet_percentage      # 32.8% per year

      ```


      ## Understanding the Simulation (`sim_`)


      The simulation calculates all loan costs before contracting:


      | Field | Description |

      |---|---|

      | `requested_amount` | Amount requested by the customer |

      | `amount` | Net amount the customer receives |

      | `interest_amount` | Total interest |

      | `fees_amount` | Total fees |

      | `iof_amount` | Calculated IOF |

      | `total_loan_amount` | Total amount (principal + interest + fees + IOF) |

      | `installments_value` | Fixed amount of each installment |

      | `cet_percentage` | Annualized Total Effective Cost |

      | `first_due_date` | Due date of the first installment |


      ## Webhooks


      | Event | When it fires |

      |---|---|

      | `credit_offer.available` | New offer generated for the customer |

      | `credit_offer.expired` | Offer expired (`valid_until` exceeded) |
    x-displayName: Credit Offers
  - name: Loans
    description: >
      The **Loan** resource (`ln_`) represents a loan originated from a

      CreditOffer and its Simulation. After creation, the loan goes through
      several

      automated steps until disbursement.


      ## Lifecycle


      ```

      processing → contract_generated → awaiting_signatures → signed →
      disbursing → active → finished
                                                                                           ↘ cancelled
                                                                                           ↘ error
      ```


      | Status | Description | Required Action |

      |---|---|---|

      | `processing` | Loan created, processing | Wait |

      | `contract_generated` | CCB generated | Wait |

      | `awaiting_signatures` | Contract ready for signing | Redirect customer
      to `signing_url` |

      | `signed` | Contract signed | Wait for disbursement |

      | `disbursing` | Disbursement in progress | Wait |

      | `active` | Disbursement completed, installments generated | Track
      payments |

      | `finished` | All installments paid | — |

      | `cancelled` | Cancelled before disbursement | — |

      | `error` | Processing error | Contact support |


      ## Example: Create and Track


      ```ruby

      # 1. Create the loan from the simulation

      loan = client.loans.create(
        credit_offer_id: "co_550e8400...",
        simulation_id: "sim_550e8400...",
        installments: 6,
        installments_value: "4550.00",
        first_due_date: "2026-04-15"
      )

      # loan.id => "ln_550e8400..."

      # loan.status => "processing"


      # 2. After loan.awaiting_signatures webhook

      loan = client.loans.retrieve(loan.id)

      # loan.signing_url => ClickSign URL for signing

      # Redirect the customer to this URL


      # 3. After loan.active webhook — check installments

      transactions = client.loans.list_transactions(loan.id)

      transactions.data.each do |tx|
        puts "#{tx.due_date}: R$ #{tx.amount_due} (#{tx.status})"
      end

      # 2026-04-15: R$ 4550.00 (pending)

      # 2026-05-15: R$ 4550.00 (pending)

      # ...

      ```


      ## Transactions (`tx_`)


      Each active loan has transactions of type `installment` — one per
      installment.

      Track payments via queries or webhooks.


      | Status | Description |

      |---|---|

      | `pending` | Installment not yet due |

      | `paid` | Installment fully paid |

      | `partially_paid` | Partial payment received |

      | `overdue` | Installment overdue (`days_overdue` > 0) |


      ## Webhooks


      | Event | When it fires |

      |---|---|

      | `loan.created` | Loan created, processing started |

      | `loan.contract_generated` | CCB generated, `ccb_number` available |

      | `loan.awaiting_signatures` | `signing_url` available for the customer |

      | `loan.signed` | Contract signed by all parties |

      | `loan.disbursing` | Disbursement via Pix started |

      | `loan.active` | Disbursement completed, installments created |

      | `loan.payment_received` | Installment payment detected |

      | `loan.finished` | All installments paid |

      | `loan.cancelled` | Loan cancelled |

      | `loan.error` | Processing error |
    x-displayName: Loans
  - name: Webhooks
    description: >
      Manage the endpoints that receive event notifications (`we_`). Dinie

      follows the [Standard Webhooks](https://www.standardwebhooks.com/)
      specification.


      Events for each resource are documented in the **Customers**, **Credit

      Offers**, and **Loans** sections. This section covers only endpoint
      management.


      ## Configuration


      ```ruby

      endpoint = client.webhooks.create_endpoint(
        url: "https://partner.example.com/webhooks/dinie",
        events: ["customer.active", "credit_offer.available", "loan.*"],
        description: "Production webhook"
      )

      # endpoint.secret => "whsec_xxxx..."

      # ⚠️ Store the secret — shown only at creation!

      ```


      ## Event Patterns


      Use `*` for all events, or `resource.*` for all events of a resource.


      | Pattern | Included Events |

      |---|---|

      | `customer.*` | `created`, `under_review`, `kyc_updated`, `active` |

      | `credit_offer.*` | `available`, `expired` |

      | `loan.*` | `created`, `contract_generated`, `awaiting_signatures`,
      `signed`, `disbursing`, `active`, `payment_received`, `finished`,
      `cancelled`, `error` |

      | `*` | All events |


      ## Secret Rotation


      Rotate the secret periodically. The previous secret remains valid for the

      specified time, allowing a seamless transition.


      ```ruby

      result = client.webhooks.rotate_secret("we_abc123",
        expire_current_in: 3600  # previous valid for 1 more hour
      )

      # result.secret => "whsec_yyyy..." (new secret)

      ```
    x-displayName: Webhooks
paths:
  /auth/token:
    post:
      operationId: createToken
      summary: Exchange credentials for an access token
      description: >
        Authenticates the partner using the OAuth2 Client Credentials flow. Send
        `client_id`

        and `client_secret` in the Authorization header (Basic Auth) to receive
        a JWT token.

        The token expires in 1 hour and must be sent as a Bearer token in all
        other requests.

        The SDKs handle token retrieval and renewal automatically.
      tags:
        - Authentication
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - grant_type
              properties:
                grant_type:
                  type: string
                  enum:
                    - client_credentials
            example:
              grant_type: client_credentials
      parameters:
        - name: Authorization
          in: header
          required: true
          description: >-
            Basic base64(client_id:client_secret) — Partner credentials encoded
            in Base64
          schema:
            type: string
      responses:
        '200':
          description: Token issued successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResponse'
              example:
                access_token: >-
                  dinie_at_eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaW5pZV9jaV81NTBlODQwMGUyOWI0MWQ0YTcxNjQ0NjY1NTQ0MDAwMCIsImV4cCI6MTcwOTU1NTYwMH0.abc123
                token_type: bearer
                expires_in: 3600
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_grant_type:
                  summary: '`grant_type` parameter is missing'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`grant_type` parameter is missing'
                    code: missing_grant_type
                unsupported_grant_type:
                  summary: '`grant_type` is not `client_credentials`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`grant_type` is not `client_credentials`'
                    code: unsupported_grant_type
                missing_authorization:
                  summary: '`Authorization` header is missing'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Authorization` header is missing'
                    code: missing_authorization
                invalid_content_type:
                  summary: '`Content-Type` is not `application/x-www-form-urlencoded`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/x-www-form-urlencoded`'
                    code: invalid_content_type
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_client:
                  summary: '`client_id` does not exist'
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: '`client_id` does not exist'
                    code: invalid_client
                invalid_client_secret:
                  summary: '`client_secret` does not match'
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: '`client_secret` does not match'
                    code: invalid_client_secret
                credential_revoked:
                  summary: Credential has been revoked
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Credential has been revoked
                    code: credential_revoked
                credential_expired:
                  summary: Credential has passed its `expires_at`
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Credential has passed its `expires_at`
                    code: credential_expired
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: |
            curl -X POST https://api.dinie.com.br/v3/auth/token \
              -u "$DINIE_CLIENT_ID:$DINIE_CLIENT_SECRET" \
              -H "Content-Type: application/x-www-form-urlencoded" \
              -d "grant_type=client_credentials"
        - lang: Python
          source: |
            from dinie import Dinie

            # The SDK handles token exchange automatically.
            # Just initialize with your credentials:
            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # To obtain a token manually (rarely needed):
            token = client.auth.create_token()

            print(token.access_token)  # "dinie_at_eyJhbG..."
            print(token.expires_in)    # 3600
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            // The SDK handles token exchange automatically.
            // Just initialize with your credentials:
            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // To obtain a token manually (rarely needed):
            const token = await client.auth.createToken();

            console.log(token.accessToken);  // "dinie_at_eyJhbG..."
            console.log(token.expiresIn);    // 3600
        - lang: Ruby
          source: |
            require "dinie"

            # The SDK handles token exchange automatically.
            # Just initialize with your credentials:
            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # To obtain a token manually (rarely needed):
            token = client.auth.create_token

            puts token.access_token  # "dinie_at_eyJhbG..."
            puts token.expires_in    # 3600
  /auth/credentials:
    post:
      operationId: createCredential
      summary: Create a new API key
      description: >
        Creates a new credential pair (`client_id` + `client_secret`) for the
        partner.

        The `client_secret` is displayed only once in the response — store it
        securely.

        Use multiple credentials to separate environments (production, staging,
        development)

        or distinct internal systems.
      tags:
        - Authentication
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCredentialRequest'
            example:
              name: Chave de Produção
              expires_at: '2027-03-04T00:00:00Z'
      responses:
        '201':
          description: Credential created
          headers:
            Location:
              schema:
                type: string
              example: /v3/auth/credentials/dinie_ci_550e8400e29b41d4a716446655440000
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialWithSecret'
              example:
                id: dinie_ci_550e8400e29b41d4a716446655440000
                client_id: dinie_ci_550e8400e29b41d4a716446655440000
                name: Chave de Produção
                status: active
                client_secret: dinie_cs_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
                expires_at: '2027-03-04T00:00:00Z'
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-04T10:00:00Z'
                last_used_at: null
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
                malformed_body:
                  summary: Request body is not valid JSON
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body is not valid JSON
                    code: malformed_body
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_required_field:
                  summary: '`name` is missing'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`name` is missing'
                    code: missing_required_field
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: |
            curl -X POST https://api.dinie.com.br/v3/auth/credentials \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -d '{
                "name": "Chave de Produção",
                "expires_at": "2027-03-04T00:00:00Z"
              }'
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Create a new API credential
            credential = client.auth.create_credential(
                name="Chave de Produção",
                expires_at="2027-03-04T00:00:00Z"
            )

            print(credential.client_id)      # "dinie_ci_550e8400..."
            print(credential.client_secret)   # "dinie_cs_live_a1b2c3..."
            # ⚠️ Store the client_secret securely -- shown only once!
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Create a new API credential
            const credential = await client.auth.createCredential({
              name: "Chave de Produção",
              expiresAt: "2027-03-04T00:00:00Z",
            });

            console.log(credential.clientId);      // "dinie_ci_550e8400..."
            console.log(credential.clientSecret);   // "dinie_cs_live_a1b2c3..."
            // Store the clientSecret securely -- shown only once!
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Create a new API credential
            credential = client.auth.create_credential(
              name: "Chave de Produção",
              expires_at: "2027-03-04T00:00:00Z"
            )

            puts credential.client_id      # "dinie_ci_550e8400..."
            puts credential.client_secret   # "dinie_cs_live_a1b2c3..."
            # Store the client_secret securely -- shown only once!
    get:
      operationId: listCredentials
      summary: List API keys
      description: >
        Returns all API keys for the authenticated partner, including name,
        creation date,

        and status (active or revoked). For security, the `client_secret` is not
        returned in this

        listing — it is displayed only at creation time via `POST
        /auth/credentials`.
      tags:
        - Authentication
      responses:
        '200':
          description: List of credentials
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - has_more
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Credential'
                  has_more:
                    type: boolean
              example:
                data:
                  - id: dinie_ci_550e8400e29b41d4a716446655440000
                    client_id: dinie_ci_550e8400e29b41d4a716446655440000
                    name: Chave de Produção
                    status: active
                    expires_at: '2027-03-04T00:00:00Z'
                    created_at: '2026-03-04T10:00:00Z'
                    updated_at: '2026-03-04T10:00:00Z'
                    last_used_at: '2026-03-05T14:30:00Z'
                has_more: false
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: |
            curl https://api.dinie.com.br/v3/auth/credentials \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # List all API credentials
            credentials = client.auth.list_credentials()

            for cred in credentials.data:
                print(f"{cred.name}: {cred.status}")
                # "Chave de Produção: active"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // List all API credentials
            const credentials = await client.auth.listCredentials();

            for (const cred of credentials.data) {
              console.log(`${cred.name}: ${cred.status}`);
              // "Chave de Produção: active"
            }
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # List all API credentials
            credentials = client.auth.list_credentials

            credentials.data.each do |cred|
              puts "#{cred.name}: #{cred.status}"
              # "Chave de Produção: active"
            end
  /auth/credentials/{client_id}:
    delete:
      operationId: revokeCredential
      summary: Revoke an API key
      description: >
        Revokes an API key immediately and irreversibly. After revocation,

        no new tokens can be issued with this credential. Tokens already issued

        before revocation remain valid until they expire (maximum 1 hour).

        Use this endpoint when decommissioning an environment or in case of
        credential leakage.
      tags:
        - Authentication
      parameters:
        - name: client_id
          in: path
          required: true
          schema:
            $ref: '#/components/schemas/ApiClientId'
      responses:
        '204':
          description: Credential revoked (empty body)
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                credential_not_found:
                  summary: >-
                    `client_id` does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      `client_id` does not exist or does not belong to this
                      partner
                    code: credential_not_found
        '409':
          description: Conflict
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                last_active_credential:
                  summary: Cannot revoke the last active credential
                  value:
                    type: https://docs.dinie.com.br/errors/conflict
                    title: Conflict
                    status: 409
                    detail: Cannot revoke the last active credential
                    code: last_active_credential
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl -X DELETE
            https://api.dinie.com.br/v3/auth/credentials/dinie_ci_550e8400e29b41d4a716446655440000
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: >
            from dinie import Dinie


            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )


            # Revoke a compromised credential

            client.auth.revoke_credential("dinie_ci_550e8400e29b41d4a716446655440000")

            # 204 No Content -- credential revoked immediately
        - lang: Node.js
          source: >
            const { Dinie } = require("dinie");


            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });


            // Revoke a compromised credential

            await
            client.auth.revokeCredential("dinie_ci_550e8400e29b41d4a716446655440000");

            // 204 No Content -- credential revoked immediately
        - lang: Ruby
          source: >
            require "dinie"


            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )


            # Revoke a compromised credential

            client.auth.revoke_credential("dinie_ci_550e8400e29b41d4a716446655440000")

            # 204 No Content -- credential revoked immediately
  /customers:
    post:
      operationId: createCustomer
      summary: Register a new customer
      description: >
        Registers a new customer (borrower) for the authenticated partner. The
        customer is created

        with status `pending_kyc` and the response includes the `kyc` array with
        the documents and

        verifications required for this profile. The next step is to submit
        documents

        via `POST /customers/{id}/documents`.


        Idempotent behavior: if the same CPF/CNPJ with the same `external_id`
        already exists,

        the existing customer is returned (`200 OK`). The `409` error occurs
        only when the

        `external_id` differs for the same CPF/CNPJ. See also the `customer.*`
        webhooks

        to track registration progress.
      tags:
        - Customers
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCustomerRequest'
            example:
              cpf: 123.456.789-00
              cnpj: 12.345.678/0001-90
              name: João Silva
              email: joao@example.com
              phone: '+5511999999999'
              trading_name: Loja do João
              external_id: partner-ref-123
      responses:
        '201':
          description: Customer created
          headers:
            Location:
              schema:
                type: string
              example: /v3/customers/cust_550e8400e29b41d4a716446655440000
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
              example:
                id: cust_550e8400e29b41d4a716446655440000
                status: pending_kyc
                cpf: 123.456.789-00
                cnpj: 12.345.678/0001-90
                name: João Silva
                email: joao@example.com
                phone: '+5511999999999'
                trading_name: Loja do João
                external_id: partner-ref-123
                kyc:
                  - kind: document
                    type: ccmei
                    description: Certificado MEI
                    status: pending
                    message: null
                    uploaded_at: null
                  - kind: document
                    type: selfie
                    description: Selfie
                    status: pending
                    message: null
                    uploaded_at: null
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-04T10:00:00Z'
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
                malformed_body:
                  summary: Request body is not valid JSON
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body is not valid JSON
                    code: malformed_body
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '409':
          description: Conflict
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                customer_already_exists:
                  summary: >-
                    Same CPF/CNPJ already registered under this partner with a
                    different `external_id`
                  value:
                    type: https://docs.dinie.com.br/errors/conflict
                    title: Conflict
                    status: 409
                    detail: >-
                      Same CPF/CNPJ already registered under this partner with a
                      different `external_id`
                    code: customer_already_exists
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_required_field:
                  summary: '`cpf` is missing (required for all customers)'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`cpf` is missing (required for all customers)'
                    code: missing_required_field
                invalid_cpf:
                  summary: CPF fails check-digit validation
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: CPF fails check-digit validation
                    code: invalid_cpf
                invalid_cnpj:
                  summary: CNPJ fails check-digit validation
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: CNPJ fails check-digit validation
                    code: invalid_cnpj
                invalid_email:
                  summary: Email format is invalid
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Email format is invalid
                    code: invalid_email
                invalid_phone:
                  summary: Phone format is invalid (expected E.164)
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Phone format is invalid (expected E.164)
                    code: invalid_phone
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: |
            curl -X POST https://api.dinie.com.br/v3/customers \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -d '{
                "cpf": "123.456.789-00",
                "name": "João Silva",
                "email": "joao@example.com",
                "phone": "+5511999999999",
                "external_id": "partner-ref-123"
              }'
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Create a new customer
            customer = client.customers.create(
                cpf="123.456.789-00",
                name="João Silva",
                email="joao@example.com",
                phone="+5511999999999",
                external_id="partner-ref-123"
            )

            print(customer.id)        # "cust_550e8400..."
            print(customer.status)    # "pending_kyc"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Create a new customer
            const customer = await client.customers.create({
              cpf: "123.456.789-00",
              name: "João Silva",
              email: "joao@example.com",
              phone: "+5511999999999",
              externalId: "partner-ref-123",
            });

            console.log(customer.id);      // "cust_550e8400..."
            console.log(customer.status);   // "pending_kyc"
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Create a new customer
            customer = client.customers.create(
              cpf: "123.456.789-00",
              name: "João Silva",
              email: "joao@example.com",
              phone: "+5511999999999",
              external_id: "partner-ref-123"
            )

            puts customer.id      # "cust_550e8400..."
            puts customer.status  # "pending_kyc"
    get:
      operationId: listCustomers
      summary: List customers
      description: >
        Lists and searches customers for the authenticated partner. Supports
        filters by `cpf`,

        `external_id`, and `status` to locate specific customers. Pagination
        uses

        cursor-based approach with the `starting_after` (last item ID) and
        `limit` (max 100) parameters.
      tags:
        - Customers
      parameters:
        - name: external_id
          in: query
          schema:
            type: string
          description: Filter by partner external reference
        - name: cpf
          in: query
          schema:
            type: string
          description: Filter by CPF
        - name: sort
          in: query
          schema:
            type: string
            enum:
              - created_at
              - updated_at
              - name
            default: created_at
        - name: order
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
        - $ref: '#/components/parameters/StartingAfter'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: List of customers
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - has_more
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Customer'
                  has_more:
                    type: boolean
              example:
                data:
                  - id: cust_550e8400e29b41d4a716446655440000
                    status: active
                    cpf: 123.456.789-00
                    cnpj: 12.345.678/0001-90
                    name: João Silva
                    email: joao@example.com
                    phone: '+5511999999999'
                    trading_name: Loja do João
                    external_id: partner-ref-123
                    kyc: []
                    created_at: '2026-03-04T10:00:00Z'
                    updated_at: '2026-03-04T12:00:00Z'
                  - id: cust_660e8400e29b41d4a716446655440001
                    status: pending_kyc
                    cpf: 987.654.321-00
                    cnpj: null
                    name: Maria Santos
                    email: maria@example.com
                    phone: '+5511988888888'
                    trading_name: null
                    external_id: partner-ref-456
                    kyc: []
                    created_at: '2026-03-05T08:00:00Z'
                    updated_at: '2026-03-05T08:00:00Z'
                has_more: true
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_limit:
                  summary: '`limit` is not a valid integer or is outside 1–100 range'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`limit` is not a valid integer or is outside 1–100 range'
                    code: invalid_limit
                invalid_sort:
                  summary: '`sort` value is not one of the supported fields'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`sort` value is not one of the supported fields'
                    code: invalid_sort
                invalid_order:
                  summary: '`order` value is not `asc` or `desc`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`order` value is not `asc` or `desc`'
                    code: invalid_order
                invalid_cursor:
                  summary: >-
                    `starting_after` references a non-existent or inaccessible
                    customer
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: >-
                      `starting_after` references a non-existent or inaccessible
                      customer
                    code: invalid_cursor
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            # List customers filtered by CPF

            curl
            "https://api.dinie.com.br/v3/customers?cpf=123.456.789-00&limit=10"
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # List customers filtered by CPF
            customers = client.customers.list(
                cpf="123.456.789-00",
                limit=10
            )

            for cust in customers.data:
                print(f"{cust.name}: {cust.status}")

            # Paginate with starting_after
            if customers.has_more:
                next_page = client.customers.list(
                    starting_after=customers.data[-1].id,
                    limit=10
                )
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // List customers filtered by CPF
            const customers = await client.customers.list({
              cpf: "123.456.789-00",
              limit: 10,
            });

            for (const cust of customers.data) {
              console.log(`${cust.name}: ${cust.status}`);
            }

            // Paginate with startingAfter
            if (customers.hasMore) {
              const nextPage = await client.customers.list({
                startingAfter: customers.data.at(-1).id,
                limit: 10,
              });
            }
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # List customers filtered by CPF
            customers = client.customers.list(
              cpf: "123.456.789-00",
              limit: 10
            )

            customers.data.each do |cust|
              puts "#{cust.name}: #{cust.status}"
            end

            # Paginate with starting_after
            if customers.has_more
              next_page = client.customers.list(
                starting_after: customers.data.last.id,
                limit: 10
              )
            end
  /customers/{customer_id}:
    get:
      operationId: getCustomer
      summary: Retrieve a customer
      description: >
        Returns the complete customer object, including registration data,
        current status,

        and the `kyc` array with the progress of each verification requirement.
        Use this endpoint

        to check the customer state at any time or after receiving a

        `customer.kyc_updated` webhook.
      tags:
        - Customers
      parameters:
        - $ref: '#/components/parameters/CustomerId'
      responses:
        '200':
          description: Customer details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
              example:
                id: cust_550e8400e29b41d4a716446655440000
                status: active
                cpf: 123.456.789-00
                cnpj: 12.345.678/0001-90
                name: João Silva
                email: joao@example.com
                phone: '+5511999999999'
                trading_name: Loja do João
                external_id: partner-ref-123
                kyc:
                  - kind: document
                    type: ccmei
                    description: Certificado MEI
                    status: approved
                    message: null
                    uploaded_at: '2026-03-04T11:00:00Z'
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-04T14:00:00Z'
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                customer_not_found:
                  summary: >-
                    Customer ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Customer ID does not exist or does not belong to this
                      partner
                    code: customer_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl
            https://api.dinie.com.br/v3/customers/cust_550e8400e29b41d4a716446655440000
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: >
            from dinie import Dinie


            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )


            # Retrieve a customer

            customer =
            client.customers.retrieve("cust_550e8400e29b41d4a716446655440000")


            print(customer.status)       # "active"

            print(customer.name)         # "João Silva"

            print(customer.external_id)  # "partner-ref-123"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Retrieve a customer
            const customer = await client.customers.retrieve(
              "cust_550e8400e29b41d4a716446655440000"
            );

            console.log(customer.status);       // "active"
            console.log(customer.name);         // "João Silva"
            console.log(customer.externalId);   // "partner-ref-123"
        - lang: Ruby
          source: >
            require "dinie"


            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )


            # Retrieve a customer

            customer =
            client.customers.retrieve("cust_550e8400e29b41d4a716446655440000")


            puts customer.status       # "active"

            puts customer.name         # "João Silva"

            puts customer.external_id  # "partner-ref-123"
    patch:
      operationId: updateCustomer
      summary: Update customer data
      description: >
        Updates customer data fields. The main use case is correcting
        information

        rejected during KYC verification (items with `pending_correction`
        status), such as

        email, phone, or registration data. The `cpf` and `external_id` fields
        cannot be

        updated after creation. After correction, the KYC analysis resumes

        automatically and you will receive `customer.kyc_updated` webhooks with
        the progress.
      tags:
        - Customers
      parameters:
        - $ref: '#/components/parameters/CustomerId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCustomerRequest'
            example:
              email: joao.novo@example.com
              phone: '+5511988887777'
      responses:
        '200':
          description: Customer updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
              example:
                id: cust_550e8400e29b41d4a716446655440000
                status: active
                cpf: 123.456.789-00
                cnpj: 12.345.678/0001-90
                name: João Silva
                email: joao.novo@example.com
                phone: '+5511988887777'
                trading_name: Loja do João
                external_id: partner-ref-123
                kyc: []
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-05T09:00:00Z'
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
                malformed_body:
                  summary: Request body is not valid JSON
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body is not valid JSON
                    code: malformed_body
                empty_update:
                  summary: Request body contains no updatable fields
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body contains no updatable fields
                    code: empty_update
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                customer_not_found:
                  summary: >-
                    Customer ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Customer ID does not exist or does not belong to this
                      partner
                    code: customer_not_found
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_email:
                  summary: Email format is invalid
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Email format is invalid
                    code: invalid_email
                invalid_phone:
                  summary: Phone format is invalid (expected E.164)
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Phone format is invalid (expected E.164)
                    code: invalid_phone
                invalid_cnpj:
                  summary: CNPJ fails check-digit validation
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: CNPJ fails check-digit validation
                    code: invalid_cnpj
                field_not_updatable:
                  summary: Attempted to update a read-only field (`cpf`, `external_id`)
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: >-
                      Attempted to update a read-only field (`cpf`,
                      `external_id`)
                    code: field_not_updatable
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl -X PATCH
            https://api.dinie.com.br/v3/customers/cust_550e8400e29b41d4a716446655440000
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -d '{
                "email": "joao.novo@example.com",
                "phone": "+5511988887777"
              }'
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Update customer data (e.g., fix rejected KYC fields)
            customer = client.customers.update(
                "cust_550e8400e29b41d4a716446655440000",
                email="joao.novo@example.com",
                phone="+5511988887777"
            )

            print(customer.email)  # "joao.novo@example.com"
            print(customer.phone)  # "+5511988887777"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Update customer data (e.g., fix rejected KYC fields)
            const customer = await client.customers.update(
              "cust_550e8400e29b41d4a716446655440000",
              {
                email: "joao.novo@example.com",
                phone: "+5511988887777",
              }
            );

            console.log(customer.email);  // "joao.novo@example.com"
            console.log(customer.phone);  // "+5511988887777"
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Update customer data (e.g., fix rejected KYC fields)
            customer = client.customers.update(
              "cust_550e8400e29b41d4a716446655440000",
              email: "joao.novo@example.com",
              phone: "+5511988887777"
            )

            puts customer.email  # "joao.novo@example.com"
            puts customer.phone  # "+5511988887777"
  /customers/{customer_id}/documents:
    post:
      operationId: uploadDocument
      summary: Upload a KYC document
      description: >
        Uploads a KYC document for the customer via file upload
        (`multipart/form-data`).

        The document type must match one of the types listed in the customer's
        `kyc` array

        (e.g., `ccmei`, `selfie`, `cnh`). After upload, the document undergoes
        asynchronous review.

        Track the result via the `customer.kyc_updated` webhook or by retrieving
        the customer

        with `GET /customers/{customer_id}`.
      tags:
        - Customers
      parameters:
        - $ref: '#/components/parameters/CustomerId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - type
                - file
              properties:
                type:
                  type: string
                  description: >-
                    KYC document type (e.g., `ccmei`, `selfie`,
                    `identity_card_front`)
                file:
                  type: string
                  format: binary
                  description: Document file (PDF, JPEG, or PNG)
      responses:
        '201':
          description: Document uploaded
          headers:
            Location:
              schema:
                type: string
              example: >-
                /v3/customers/cust_550e8400e29b41d4a716446655440000/documents/doc_550e8400e29b41d4a716446655440001
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Document'
              example:
                id: doc_550e8400e29b41d4a716446655440001
                type: ccmei
                status: submitted
                uploaded_at: '2026-03-04T11:00:00Z'
                created_at: '2026-03-04T11:00:00Z'
                updated_at: '2026-03-04T11:00:00Z'
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `multipart/form-data`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `multipart/form-data`'
                    code: invalid_content_type
                missing_file:
                  summary: '`file` part is missing from the multipart request'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`file` part is missing from the multipart request'
                    code: missing_file
                missing_type:
                  summary: '`type` field is missing'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`type` field is missing'
                    code: missing_type
                file_too_large:
                  summary: File exceeds the maximum allowed size
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: File exceeds the maximum allowed size
                    code: file_too_large
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                customer_not_found:
                  summary: >-
                    Customer ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Customer ID does not exist or does not belong to this
                      partner
                    code: customer_not_found
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_document_type:
                  summary: >-
                    `type` is not a valid KYC requirement for this customer's
                    partner/tax regime
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: >-
                      `type` is not a valid KYC requirement for this customer's
                      partner/tax regime
                    code: invalid_document_type
                invalid_file_format:
                  summary: File format is not supported (expected PDF, JPEG, or PNG)
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: File format is not supported (expected PDF, JPEG, or PNG)
                    code: invalid_file_format
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl -X POST
            https://api.dinie.com.br/v3/customers/cust_550e8400e29b41d4a716446655440000/documents
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -F "type=ccmei" \
              -F "file=@certificado-mei.pdf"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Upload a KYC document
            document = client.customers.upload_document(
                "cust_550e8400e29b41d4a716446655440000",
                type="ccmei",
                file=open("certificado-mei.pdf", "rb")
            )

            print(document.id)      # "doc_550e8400..."
            print(document.status)  # "submitted"
        - lang: Node.js
          source: |
            const fs = require("fs");
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Upload a KYC document
            const document = await client.customers.uploadDocument(
              "cust_550e8400e29b41d4a716446655440000",
              {
                type: "ccmei",
                file: fs.createReadStream("certificado-mei.pdf"),
              }
            );

            console.log(document.id);      // "doc_550e8400..."
            console.log(document.status);   // "submitted"
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Upload a KYC document
            document = client.customers.upload_document(
              "cust_550e8400e29b41d4a716446655440000",
              type: "ccmei",
              file: File.open("certificado-mei.pdf")
            )

            puts document.id      # "doc_550e8400..."
            puts document.status  # "submitted"
  /customers/{customer_id}/biometrics:
    post:
      operationId: createBiometricsSession
      summary: Generate a biometric capture session
      description: >
        Creates a biometrics capture session for the customer and returns a
        temporary URL.

        The partner should redirect the customer to this URL or embed it in a
        webview

        within their application. Biometrics is a KYC requirement of type
        `biometrics` and its

        progress is tracked in the customer's `kyc` array. This is an action
        endpoint that

        returns `200 OK` (not `201 Created`). See the `customer.kyc_updated`
        webhook to

        track the completion of the capture.
      tags:
        - Customers
      parameters:
        - $ref: '#/components/parameters/CustomerId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Biometrics session created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BiometricsSession'
              example:
                session_url: https://biometrics.dinie.com.br/session/abc123def456
                expires_at: '2026-03-04T16:00:00Z'
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                customer_not_found:
                  summary: >-
                    Customer ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Customer ID does not exist or does not belong to this
                      partner
                    code: customer_not_found
        '409':
          description: Conflict
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                session_already_active:
                  summary: A biometrics session is already active for this customer
                  value:
                    type: https://docs.dinie.com.br/errors/conflict
                    title: Conflict
                    status: 409
                    detail: A biometrics session is already active for this customer
                    code: session_already_active
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                biometrics_not_required:
                  summary: Customer does not have pending biometrics KYC requirements
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Customer does not have pending biometrics KYC requirements
                    code: biometrics_not_required
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl -X POST
            https://api.dinie.com.br/v3/customers/cust_550e8400e29b41d4a716446655440000/biometrics
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: >
            from dinie import Dinie


            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )


            # Generate a biometrics capture session

            session = client.customers.create_biometrics_session(
                "cust_550e8400e29b41d4a716446655440000"
            )


            print(session.session_url)  #
            "https://biometrics.dinie.com.br/session/abc123def456"

            print(session.expires_at)   # "2026-03-04T16:00:00Z"

            # Redirect the customer to session.session_url
        - lang: Node.js
          source: >
            const { Dinie } = require("dinie");


            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });


            // Generate a biometrics capture session

            const session = await client.customers.createBiometricsSession(
              "cust_550e8400e29b41d4a716446655440000"
            );


            console.log(session.sessionUrl);  //
            "https://biometrics.dinie.com.br/session/abc123def456"

            console.log(session.expiresAt);   // "2026-03-04T16:00:00Z"

            // Redirect the customer to session.sessionUrl
        - lang: Ruby
          source: >
            require "dinie"


            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )


            # Generate a biometrics capture session

            session = client.customers.create_biometrics_session(
              "cust_550e8400e29b41d4a716446655440000"
            )


            puts session.session_url  #
            "https://biometrics.dinie.com.br/session/abc123def456"

            puts session.expires_at   # "2026-03-04T16:00:00Z"

            # Redirect the customer to session.session_url
  /customers/{customer_id}/credit-offers:
    get:
      operationId: listCustomerCreditOffers
      summary: List credit offers for a customer
      description: >
        Lists the available credit offers for a specific customer. Filterable by

        `status` (available, accepted, expired). Use this endpoint after
        receiving the

        `customer.active` webhook to check for pre-approved offers. Pagination
        uses cursor

        with `starting_after` + `limit`.
      tags:
        - Credit Offers
      parameters:
        - $ref: '#/components/parameters/CustomerId'
        - name: status
          in: query
          schema:
            type: string
            enum:
              - available
              - accepted
              - expired
        - $ref: '#/components/parameters/StartingAfter'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: List of credit offers
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - has_more
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CreditOffer'
                  has_more:
                    type: boolean
              example:
                data:
                  - id: co_550e8400e29b41d4a716446655440000
                    customer_id: cust_550e8400e29b41d4a716446655440000
                    status: available
                    approved_amount: '50000.00'
                    min_amount: '1000.00'
                    interest_rate: 3.5
                    installments: 12
                    due_date_rule: null
                    valid_until: '2026-04-01T23:59:59Z'
                    created_at: '2026-03-04T10:00:00Z'
                    updated_at: '2026-03-04T10:00:00Z'
                has_more: false
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                customer_not_found:
                  summary: >-
                    Customer ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Customer ID does not exist or does not belong to this
                      partner
                    code: customer_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl
            "https://api.dinie.com.br/v3/customers/cust_550e8400e29b41d4a716446655440000/credit-offers?status=available"
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # List available credit offers for a customer
            offers = client.customers.list_credit_offers(
                "cust_550e8400e29b41d4a716446655440000",
                status="available"
            )

            for offer in offers.data:
                print(f"{offer.id}: R$ {offer.approved_amount} ({offer.interest_rate}% a.m.)")
                # "co_550e8400...: R$ 50000.00 (3.5% a.m.)"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // List available credit offers for a customer
            const offers = await client.customers.listCreditOffers(
              "cust_550e8400e29b41d4a716446655440000",
              { status: "available" }
            );

            for (const offer of offers.data) {
              console.log(`${offer.id}: R$ ${offer.approvedAmount} (${offer.interestRate}% a.m.)`);
              // "co_550e8400...: R$ 50000.00 (3.5% a.m.)"
            }
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # List available credit offers for a customer
            offers = client.customers.list_credit_offers(
              "cust_550e8400e29b41d4a716446655440000",
              status: "available"
            )

            offers.data.each do |offer|
              puts "#{offer.id}: R$ #{offer.approved_amount} (#{offer.interest_rate}% a.m.)"
              # "co_550e8400...: R$ 50000.00 (3.5% a.m.)"
            end
  /credit-offers:
    get:
      operationId: listCreditOffers
      summary: List credit offers
      description: >
        Lists credit offers for all customers of the authenticated partner.
        Supports filters

        by `customer_id` and `status` to locate specific offers. Useful for
        dashboards

        and reports that need a consolidated view. For offers of a specific
        customer,

        prefer `GET /customers/{customer_id}/credit-offers`.
      tags:
        - Credit Offers
      parameters:
        - name: customer_id
          in: query
          schema:
            $ref: '#/components/schemas/CustomerId'
          description: Filter by customer
        - name: status
          in: query
          schema:
            type: string
            enum:
              - available
              - accepted
              - expired
        - $ref: '#/components/parameters/StartingAfter'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: List of credit offers
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - has_more
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CreditOffer'
                  has_more:
                    type: boolean
              example:
                data:
                  - id: co_550e8400e29b41d4a716446655440000
                    customer_id: cust_550e8400e29b41d4a716446655440000
                    status: available
                    approved_amount: '50000.00'
                    min_amount: '1000.00'
                    interest_rate: 3.5
                    installments: 12
                    due_date_rule: null
                    valid_until: '2026-04-01T23:59:59Z'
                    created_at: '2026-03-04T10:00:00Z'
                    updated_at: '2026-03-04T10:00:00Z'
                has_more: false
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_limit:
                  summary: '`limit` is not a valid integer or is outside 1–100 range'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`limit` is not a valid integer or is outside 1–100 range'
                    code: invalid_limit
                invalid_cursor:
                  summary: >-
                    `starting_after` references a non-existent or inaccessible
                    credit offer
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: >-
                      `starting_after` references a non-existent or inaccessible
                      credit offer
                    code: invalid_cursor
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                customer_not_found:
                  summary: >-
                    `customer_id` filter references a non-existent or
                    inaccessible customer
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      `customer_id` filter references a non-existent or
                      inaccessible customer
                    code: customer_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            # List all available credit offers

            curl
            "https://api.dinie.com.br/v3/credit-offers?status=available&limit=10"
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # List all available credit offers across customers
            offers = client.credit_offers.list(
                status="available",
                limit=10
            )

            for offer in offers.data:
                print(f"Customer {offer.customer_id}: R$ {offer.approved_amount}")

            # Filter by specific customer
            offers = client.credit_offers.list(
                customer_id="cust_550e8400e29b41d4a716446655440000",
                status="available"
            )
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // List all available credit offers across customers
            const offers = await client.creditOffers.list({
              status: "available",
              limit: 10,
            });

            for (const offer of offers.data) {
              console.log(`Customer ${offer.customerId}: R$ ${offer.approvedAmount}`);
            }

            // Filter by specific customer
            const filtered = await client.creditOffers.list({
              customerId: "cust_550e8400e29b41d4a716446655440000",
              status: "available",
            });
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # List all available credit offers across customers
            offers = client.credit_offers.list(
              status: "available",
              limit: 10
            )

            offers.data.each do |offer|
              puts "Customer #{offer.customer_id}: R$ #{offer.approved_amount}"
            end

            # Filter by specific customer
            offers = client.credit_offers.list(
              customer_id: "cust_550e8400e29b41d4a716446655440000",
              status: "available"
            )
  /credit-offers/{credit_offer_id}:
    get:
      operationId: getCreditOffer
      summary: Retrieve a credit offer
      description: >
        Returns the complete credit offer object, including approved amount

        (`approved_amount`), minimum amount, interest rate (`interest_rate`),
        maximum number

        of installments, and expiration date (`valid_until`). Query the offer
        before creating

        a simulation to present the limits to the customer.
      tags:
        - Credit Offers
      parameters:
        - $ref: '#/components/parameters/CreditOfferId'
      responses:
        '200':
          description: Credit offer details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreditOffer'
              example:
                id: co_550e8400e29b41d4a716446655440000
                customer_id: cust_550e8400e29b41d4a716446655440000
                status: available
                approved_amount: '50000.00'
                min_amount: '1000.00'
                interest_rate: 3.5
                installments: 12
                due_date_rule: null
                valid_until: '2026-04-01T23:59:59Z'
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-04T10:00:00Z'
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                credit_offer_not_found:
                  summary: >-
                    Credit offer ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Credit offer ID does not exist or does not belong to this
                      partner
                    code: credit_offer_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl
            https://api.dinie.com.br/v3/credit-offers/co_550e8400e29b41d4a716446655440000
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: >
            from dinie import Dinie


            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )


            # Retrieve a credit offer

            offer =
            client.credit_offers.retrieve("co_550e8400e29b41d4a716446655440000")


            print(offer.approved_amount)  # "50000.00"

            print(offer.min_amount)       # "1000.00"

            print(offer.interest_rate)    # 3.5

            print(offer.valid_until)      # "2026-04-01T23:59:59Z"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Retrieve a credit offer
            const offer = await client.creditOffers.retrieve(
              "co_550e8400e29b41d4a716446655440000"
            );

            console.log(offer.approvedAmount);  // "50000.00"
            console.log(offer.minAmount);       // "1000.00"
            console.log(offer.interestRate);    // 3.5
            console.log(offer.validUntil);      // "2026-04-01T23:59:59Z"
        - lang: Ruby
          source: >
            require "dinie"


            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )


            # Retrieve a credit offer

            offer =
            client.credit_offers.retrieve("co_550e8400e29b41d4a716446655440000")


            puts offer.approved_amount  # "50000.00"

            puts offer.min_amount       # "1000.00"

            puts offer.interest_rate    # 3.5

            puts offer.valid_until      # "2026-04-01T23:59:59Z"
  /credit-offers/{credit_offer_id}/simulations:
    post:
      operationId: createSimulation
      summary: Simulate a loan
      description: >
        Simulates a loan scenario for a specific credit offer. The customer can

        simulate multiple times with different amounts and terms before
        committing.

        The simulation is synchronous and returns installment amounts, fees, and
        total cost. The result

        is persisted and can be referenced when creating the loan via
        `simulation_id`.

        Only the latest simulation is valid for contracting (Last Write Record).
      tags:
        - Loans
      parameters:
        - $ref: '#/components/parameters/CreditOfferId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSimulationRequest'
            example:
              requested_amount: '25000.00'
              installment_count: 12
      responses:
        '201':
          description: Simulation created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Simulation'
              example:
                id: sim_550e8400e29b41d4a716446655440001
                credit_offer_id: co_550e8400e29b41d4a716446655440000
                requested_amount: '25000.00'
                amount: '24250.00'
                interest_amount: '2750.00'
                fees_amount: '300.00'
                iof_amount: '450.00'
                total_loan_amount: '27500.00'
                interest_percentage: 3.5
                cet_percentage: 4.12
                number_of_installments: 12
                installments_value: '2291.67'
                first_due_date: '2026-04-03'
                created_at: '2026-03-04T10:30:00Z'
        '400':
          description: Invalid request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
                malformed_body:
                  summary: Request body is not valid JSON
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body is not valid JSON
                    code: malformed_body
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                credit_offer_not_found:
                  summary: >-
                    Credit offer ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Credit offer ID does not exist or does not belong to this
                      partner
                    code: credit_offer_not_found
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                offer_expired:
                  summary: Credit offer status is `expired`
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Credit offer status is `expired`
                    code: offer_expired
                offer_already_accepted:
                  summary: Credit offer status is `accepted`
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Credit offer status is `accepted`
                    code: offer_already_accepted
                invalid_amount:
                  summary: >-
                    `requested_amount` exceeds `approved_amount`, is below
                    `min_amount`, or is not a valid monetary value
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: >-
                      `requested_amount` exceeds `approved_amount`, is below
                      `min_amount`, or is not a valid monetary value
                    code: invalid_amount
                invalid_installments:
                  summary: '`installment_count` is outside the allowed range'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`installment_count` is outside the allowed range'
                    code: invalid_installments
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          description: Internal server error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                bmp_unavailable:
                  summary: BMP simulation service is temporarily unavailable
                  value:
                    type: https://docs.dinie.com.br/errors/internal
                    title: Internal Error
                    status: 500
                    detail: BMP simulation service is temporarily unavailable
                    code: bmp_unavailable
      x-codeSamples:
        - lang: curl
          source: >
            curl -X POST
            https://api.dinie.com.br/v3/credit-offers/co_550e8400e29b41d4a716446655440000/simulations
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -d '{
                "requested_amount": "25000.00",
                "installment_count": 12
              }'
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Simulate a loan scenario
            simulation = client.credit_offers.simulate(
                "co_550e8400e29b41d4a716446655440000",
                requested_amount="25000.00",
                installment_count=12
            )

            print(simulation.id)                  # "sim_550e8400..."
            print(simulation.installments_value)   # "2291.67"
            print(simulation.cet_percentage)       # 4.12
            print(simulation.total_loan_amount)    # "27500.00"
            print(simulation.first_due_date)       # "2026-04-03"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Simulate a loan scenario
            const simulation = await client.creditOffers.simulate(
              "co_550e8400e29b41d4a716446655440000",
              {
                requestedAmount: "25000.00",
                installmentCount: 12,
              }
            );

            console.log(simulation.id);                  // "sim_550e8400..."
            console.log(simulation.installmentsValue);   // "2291.67"
            console.log(simulation.cetPercentage);       // 4.12
            console.log(simulation.totalLoanAmount);     // "27500.00"
            console.log(simulation.firstDueDate);        // "2026-04-03"
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Simulate a loan scenario
            simulation = client.credit_offers.simulate(
              "co_550e8400e29b41d4a716446655440000",
              requested_amount: "25000.00",
              installment_count: 12
            )

            puts simulation.id                  # "sim_550e8400..."
            puts simulation.installments_value   # "2291.67"
            puts simulation.cet_percentage       # 4.12
            puts simulation.total_loan_amount    # "27500.00"
            puts simulation.first_due_date       # "2026-04-03"
  /loans:
    post:
      operationId: createLoan
      summary: Create a loan
      description: >
        Creates a loan from a credit offer and a simulation accepted by the

        customer. The partner must include the `simulation_id` to link the
        agreed terms.

        The loan starts with status `processing` and automatically progresses
        through the cycle:

        `contract_generated` → `awaiting_signatures` → `signed` → `disbursing` →
        `active`.

        The `signing_url` for signing the CCB contract will be made available
        via webhook

        `loan.contract_generated`. Track the lifecycle via `loan.*` webhooks.
      tags:
        - Loans
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateLoanRequest'
            example:
              credit_offer_id: co_550e8400e29b41d4a716446655440000
              simulation_id: sim_550e8400e29b41d4a716446655440001
              installments: 12
              installments_value: '2291.67'
              first_due_date: '2026-04-03'
      responses:
        '201':
          description: Loan created
          headers:
            Location:
              schema:
                type: string
              example: /v3/loans/ln_550e8400e29b41d4a716446655440001
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Loan'
              example:
                id: ln_550e8400e29b41d4a716446655440001
                credit_offer_id: co_550e8400e29b41d4a716446655440000
                simulation_id: sim_550e8400e29b41d4a716446655440001
                customer_id: cust_550e8400e29b41d4a716446655440000
                status: processing
                requested_amount: '25000.00'
                net_amount: null
                iof: null
                service_fee: null
                interest_rate: 3.5
                cet: 4.25
                total_amount: '30000.00'
                installments_value: '2291.67'
                first_due_date: '2026-04-03'
                number_of_installments: 12
                ccb_number: null
                disbursement_method: null
                signing_url: null
                created_at: '2026-03-04T11:00:00Z'
                updated_at: '2026-03-04T11:00:00Z'
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
                malformed_body:
                  summary: Request body is not valid JSON
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body is not valid JSON
                    code: malformed_body
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                credit_offer_not_found:
                  summary: >-
                    `credit_offer_id` does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      `credit_offer_id` does not exist or does not belong to
                      this partner
                    code: credit_offer_not_found
        '409':
          description: Conflict
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                offer_already_accepted:
                  summary: A loan already exists for this credit offer
                  value:
                    type: https://docs.dinie.com.br/errors/conflict
                    title: Conflict
                    status: 409
                    detail: A loan already exists for this credit offer
                    code: offer_already_accepted
                withdrawal_locked:
                  summary: >-
                    Another withdrawal is being processed for this customer
                    (concurrent lock)
                  value:
                    type: https://docs.dinie.com.br/errors/conflict
                    title: Conflict
                    status: 409
                    detail: >-
                      Another withdrawal is being processed for this customer
                      (concurrent lock)
                    code: withdrawal_locked
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_required_field:
                  summary: >-
                    Required field is missing (`credit_offer_id`,
                    `simulation_id`, `installments`, `installments_value`,
                    `first_due_date`)
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: >-
                      Required field is missing (`credit_offer_id`,
                      `simulation_id`, `installments`, `installments_value`,
                      `first_due_date`)
                    code: missing_required_field
                offer_expired:
                  summary: >-
                    Credit offer has expired (`valid_until` has passed or
                    superseded)
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: >-
                      Credit offer has expired (`valid_until` has passed or
                      superseded)
                    code: offer_expired
                kyc_incomplete:
                  summary: Customer has pending or rejected KYC requirements
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: Customer has pending or rejected KYC requirements
                    code: kyc_incomplete
                invalid_amount:
                  summary: >-
                    `amount` exceeds `approved_amount` or is not a valid
                    monetary value
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: >-
                      `amount` exceeds `approved_amount` or is not a valid
                      monetary value
                    code: invalid_amount
                invalid_installments:
                  summary: '`number_of_installments` is outside the allowed range'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`number_of_installments` is outside the allowed range'
                    code: invalid_installments
                simulation_mismatch:
                  summary: >-
                    `installments`, `installments_value`, or `first_due_date` do
                    not match the referenced simulation
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: >-
                      `installments`, `installments_value`, or `first_due_date`
                      do not match the referenced simulation
                    code: simulation_mismatch
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: |
            curl -X POST https://api.dinie.com.br/v3/loans \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -H "Idempotency-Key: unique-request-id" \
              -d '{
                "credit_offer_id": "co_550e8400e29b41d4a716446655440000",
                "simulation_id": "sim_550e8400e29b41d4a716446655440001",
                "installments": 12,
                "installments_value": "2291.67",
                "first_due_date": "2026-04-03"
              }'
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Create a loan from a simulation
            loan = client.loans.create(
                credit_offer_id="co_550e8400e29b41d4a716446655440000",
                simulation_id="sim_550e8400e29b41d4a716446655440001",
                installments=12,
                installments_value="2291.67",
                first_due_date="2026-04-03",
                idempotency_key="unique-request-id"
            )

            print(loan.id)      # "ln_550e8400..."
            print(loan.status)  # "processing"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Create a loan from a simulation
            const loan = await client.loans.create({
              creditOfferId: "co_550e8400e29b41d4a716446655440000",
              simulationId: "sim_550e8400e29b41d4a716446655440001",
              installments: 12,
              installmentsValue: "2291.67",
              firstDueDate: "2026-04-03",
              idempotencyKey: "unique-request-id",
            });

            console.log(loan.id);      // "ln_550e8400..."
            console.log(loan.status);  // "processing"
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Create a loan from a simulation
            loan = client.loans.create(
              credit_offer_id: "co_550e8400e29b41d4a716446655440000",
              simulation_id: "sim_550e8400e29b41d4a716446655440001",
              installments: 12,
              installments_value: "2291.67",
              first_due_date: "2026-04-03",
              idempotency_key: "unique-request-id"
            )

            puts loan.id      # "ln_550e8400..."
            puts loan.status  # "processing"
  /loans/{loan_id}:
    get:
      operationId: getLoan
      summary: Retrieve a loan
      description: >
        Returns the complete loan object with all lifecycle details.

        Important fields vary by status: `signing_url` is populated when

        `awaiting_signatures`, `ccb_number` when `contract_generated`, and
        `net_amount`

        after disbursement. Use together with `loan.*` webhooks to keep your
        system

        synchronized.
      tags:
        - Loans
      parameters:
        - $ref: '#/components/parameters/LoanId'
      responses:
        '200':
          description: Loan details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Loan'
              example:
                id: ln_550e8400e29b41d4a716446655440001
                credit_offer_id: co_550e8400e29b41d4a716446655440000
                simulation_id: sim_550e8400e29b41d4a716446655440001
                customer_id: cust_550e8400e29b41d4a716446655440000
                status: active
                requested_amount: '25000.00'
                net_amount: '24250.00'
                iof: '450.00'
                service_fee: '300.00'
                interest_rate: 3.5
                cet: 4.25
                total_amount: '30000.00'
                installments_value: '2291.67'
                first_due_date: '2026-04-03'
                number_of_installments: 12
                ccb_number: CCB-2026-001234
                disbursement_method: pix
                signing_url: null
                created_at: '2026-03-04T11:00:00Z'
                updated_at: '2026-03-05T14:00:00Z'
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                loan_not_found:
                  summary: Loan ID does not exist or does not belong to this partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: Loan ID does not exist or does not belong to this partner
                    code: loan_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl
            https://api.dinie.com.br/v3/loans/ln_550e8400e29b41d4a716446655440001
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Retrieve a loan
            loan = client.loans.retrieve("ln_550e8400e29b41d4a716446655440001")

            print(loan.status)              # "active"
            print(loan.requested_amount)    # "25000.00"
            print(loan.net_amount)          # "24250.00"
            print(loan.ccb_number)          # "CCB-2026-001234"
            print(loan.signing_url)         # None (already signed)
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Retrieve a loan
            const loan = await client.loans.retrieve(
              "ln_550e8400e29b41d4a716446655440001"
            );

            console.log(loan.status);              // "active"
            console.log(loan.requestedAmount);     // "25000.00"
            console.log(loan.netAmount);           // "24250.00"
            console.log(loan.ccbNumber);           // "CCB-2026-001234"
            console.log(loan.signingUrl);          // null (already signed)
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Retrieve a loan
            loan = client.loans.retrieve("ln_550e8400e29b41d4a716446655440001")

            puts loan.status              # "active"
            puts loan.requested_amount    # "25000.00"
            puts loan.net_amount          # "24250.00"
            puts loan.ccb_number          # "CCB-2026-001234"
            puts loan.signing_url         # nil (already signed)
  /loans/{loan_id}/transactions:
    get:
      operationId: listTransactions
      summary: List loan transactions
      description: >
        Lists the transactions (installments) of a loan. Each transaction
        represents an

        installment with due date (`due_date`), original amount, paid amount,
        and payment

        status (`pending`, `paid`, `overdue`). This is a read-only endpoint —

        payments are processed outside the API. Track payments in real time via

        webhook `loan.payment_received`.
      tags:
        - Loans
      parameters:
        - $ref: '#/components/parameters/LoanId'
        - $ref: '#/components/parameters/StartingAfter'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: List of transactions
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - has_more
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Transaction'
                  has_more:
                    type: boolean
              example:
                data:
                  - id: tx_550e8400e29b41d4a716446655440000
                    loan_id: ln_550e8400e29b41d4a716446655440001
                    type: installment
                    due_date: '2026-04-03'
                    status: paid
                    amount_due: '2500.00'
                    amount_paid: '2500.00'
                    amount_remaining: '0.00'
                    principal: '2083.33'
                    interest: '375.00'
                    fees: '41.67'
                    days_overdue: 0
                    paid_at: '2026-04-03T10:00:00Z'
                    created_at: '2026-03-04T11:00:00Z'
                    updated_at: '2026-04-03T10:00:00Z'
                  - id: tx_660e8400e29b41d4a716446655440001
                    loan_id: ln_550e8400e29b41d4a716446655440001
                    type: installment
                    due_date: '2026-05-03'
                    status: pending
                    amount_due: '2500.00'
                    amount_paid: '0.00'
                    amount_remaining: '2500.00'
                    principal: '2083.33'
                    interest: '375.00'
                    fees: '41.67'
                    days_overdue: 0
                    paid_at: null
                    created_at: '2026-03-04T11:00:00Z'
                    updated_at: '2026-03-04T11:00:00Z'
                has_more: true
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_limit:
                  summary: '`limit` is not a valid integer or is outside 1–100 range'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`limit` is not a valid integer or is outside 1–100 range'
                    code: invalid_limit
                invalid_cursor:
                  summary: '`starting_after` references a non-existent transaction'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`starting_after` references a non-existent transaction'
                    code: invalid_cursor
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                loan_not_found:
                  summary: Loan ID does not exist or does not belong to this partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: Loan ID does not exist or does not belong to this partner
                    code: loan_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl
            "https://api.dinie.com.br/v3/loans/ln_550e8400e29b41d4a716446655440001/transactions?limit=25"
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # List installments for a loan
            transactions = client.loans.list_transactions(
                "ln_550e8400e29b41d4a716446655440001",
                limit=25
            )

            for tx in transactions.data:
                print(f"{tx.due_date}: R$ {tx.amount_due} ({tx.status})")
                # "2026-04-03: R$ 2500.00 (paid)"
                # "2026-05-03: R$ 2500.00 (pending)"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // List installments for a loan
            const transactions = await client.loans.listTransactions(
              "ln_550e8400e29b41d4a716446655440001",
              { limit: 25 }
            );

            for (const tx of transactions.data) {
              console.log(`${tx.dueDate}: R$ ${tx.amountDue} (${tx.status})`);
              // "2026-04-03: R$ 2500.00 (paid)"
              // "2026-05-03: R$ 2500.00 (pending)"
            }
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # List installments for a loan
            transactions = client.loans.list_transactions(
              "ln_550e8400e29b41d4a716446655440001",
              limit: 25
            )

            transactions.data.each do |tx|
              puts "#{tx.due_date}: R$ #{tx.amount_due} (#{tx.status})"
              # "2026-04-03: R$ 2500.00 (paid)"
              # "2026-05-03: R$ 2500.00 (pending)"
            end
  /webhooks/endpoints:
    post:
      operationId: createWebhookEndpoint
      summary: Create a webhook endpoint
      description: >
        Creates a new webhook endpoint to receive Dinie events. The HMAC

        signing secret (`secret`) is returned only in this response — store it

        securely to validate the signatures of received events. Use event
        patterns

        like `loan.*`, `customer.*`, or `*` to subscribe to entire categories.
        Each endpoint

        can subscribe to multiple event patterns.
      tags:
        - Webhooks
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookEndpointRequest'
            example:
              url: https://parceiro.example.com/webhooks/dinie
              events:
                - customer.active
                - credit_offer.available
                - loan.*
              description: Webhook de produção
      responses:
        '201':
          description: Webhook endpoint created
          headers:
            Location:
              schema:
                type: string
              example: /v3/webhooks/endpoints/we_550e8400e29b41d4a716446655440000
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointWithSecret'
              example:
                id: we_550e8400e29b41d4a716446655440000
                url: https://parceiro.example.com/webhooks/dinie
                events:
                  - customer.active
                  - credit_offer.available
                  - loan.*
                description: Webhook de produção
                status: active
                secret: whsec_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-04T10:00:00Z'
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
                malformed_body:
                  summary: Request body is not valid JSON
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body is not valid JSON
                    code: malformed_body
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_required_field:
                  summary: '`url` is missing'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`url` is missing'
                    code: missing_required_field
                invalid_url:
                  summary: '`url` is not a valid HTTPS URL'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`url` is not a valid HTTPS URL'
                    code: invalid_url
                invalid_events:
                  summary: '`events` contains unrecognized event types'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`events` contains unrecognized event types'
                    code: invalid_events
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: |
            curl -X POST https://api.dinie.com.br/v3/webhooks/endpoints \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -d '{
                "url": "https://parceiro.example.com/webhooks/dinie",
                "events": ["customer.active", "credit_offer.available", "loan.*"],
                "description": "Webhook de produção"
              }'
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Create a webhook endpoint
            endpoint = client.webhooks.create_endpoint(
                url="https://parceiro.example.com/webhooks/dinie",
                events=["customer.active", "credit_offer.available", "loan.*"],
                description="Webhook de produção"
            )

            print(endpoint.id)      # "we_550e8400..."
            print(endpoint.secret)  # "whsec_a1b2c3..."
            # Store the secret securely -- shown only once!
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Create a webhook endpoint
            const endpoint = await client.webhooks.createEndpoint({
              url: "https://parceiro.example.com/webhooks/dinie",
              events: ["customer.active", "credit_offer.available", "loan.*"],
              description: "Webhook de produção",
            });

            console.log(endpoint.id);      // "we_550e8400..."
            console.log(endpoint.secret);   // "whsec_a1b2c3..."
            // Store the secret securely -- shown only once!
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Create a webhook endpoint
            endpoint = client.webhooks.create_endpoint(
              url: "https://parceiro.example.com/webhooks/dinie",
              events: ["customer.active", "credit_offer.available", "loan.*"],
              description: "Webhook de produção"
            )

            puts endpoint.id      # "we_550e8400..."
            puts endpoint.secret  # "whsec_a1b2c3..."
            # Store the secret securely -- shown only once!
    get:
      operationId: listWebhookEndpoints
      summary: List webhook endpoints
      description: >
        Lists all webhook endpoints configured by the partner, including URL,

        subscribed events, and status (active/disabled). The signing secret is
        not

        returned in this listing. Use to audit and manage your webhook
        integrations.
      tags:
        - Webhooks
      responses:
        '200':
          description: List of webhook endpoints
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - has_more
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebhookEndpoint'
                  has_more:
                    type: boolean
              example:
                data:
                  - id: we_550e8400e29b41d4a716446655440000
                    url: https://parceiro.example.com/webhooks/dinie
                    events:
                      - customer.active
                      - credit_offer.available
                      - loan.*
                    description: Webhook de produção
                    status: active
                    created_at: '2026-03-04T10:00:00Z'
                    updated_at: '2026-03-04T10:00:00Z'
                has_more: false
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: |
            curl https://api.dinie.com.br/v3/webhooks/endpoints \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # List all webhook endpoints
            endpoints = client.webhooks.list_endpoints()

            for ep in endpoints.data:
                print(f"{ep.id}: {ep.url} ({ep.status})")
                # "we_550e8400...: https://parceiro.example.com/webhooks/dinie (active)"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // List all webhook endpoints
            const endpoints = await client.webhooks.listEndpoints();

            for (const ep of endpoints.data) {
              console.log(`${ep.id}: ${ep.url} (${ep.status})`);
              // "we_550e8400...: https://parceiro.example.com/webhooks/dinie (active)"
            }
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # List all webhook endpoints
            endpoints = client.webhooks.list_endpoints

            endpoints.data.each do |ep|
              puts "#{ep.id}: #{ep.url} (#{ep.status})"
              # "we_550e8400...: https://parceiro.example.com/webhooks/dinie (active)"
            end
  /webhooks/endpoints/{webhook_endpoint_id}:
    get:
      operationId: getWebhookEndpoint
      summary: Retrieve a webhook endpoint
      description: >
        Returns the details of a specific webhook endpoint, including URL, list
        of

        subscribed events, and current status (active/disabled). The signing
        secret (`secret`)

        is not returned — use `POST .../secret/rotate` if you need to generate a
        new one.
      tags:
        - Webhooks
      parameters:
        - $ref: '#/components/parameters/WebhookEndpointId'
      responses:
        '200':
          description: Webhook endpoint details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpoint'
              example:
                id: we_550e8400e29b41d4a716446655440000
                url: https://parceiro.example.com/webhooks/dinie
                events:
                  - customer.active
                  - credit_offer.available
                  - loan.*
                description: Webhook de produção
                status: active
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-04T10:00:00Z'
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                webhook_endpoint_not_found:
                  summary: >-
                    Endpoint ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Endpoint ID does not exist or does not belong to this
                      partner
                    code: webhook_endpoint_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl
            https://api.dinie.com.br/v3/webhooks/endpoints/we_550e8400e29b41d4a716446655440000
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: >
            from dinie import Dinie


            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )


            # Retrieve a webhook endpoint

            endpoint = client.webhooks.retrieve_endpoint(
                "we_550e8400e29b41d4a716446655440000"
            )


            print(endpoint.url)     #
            "https://parceiro.example.com/webhooks/dinie"

            print(endpoint.events)  # ["customer.active",
            "credit_offer.available", "loan.*"]

            print(endpoint.status)  # "active"
        - lang: Node.js
          source: >
            const { Dinie } = require("dinie");


            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });


            // Retrieve a webhook endpoint

            const endpoint = await client.webhooks.retrieveEndpoint(
              "we_550e8400e29b41d4a716446655440000"
            );


            console.log(endpoint.url);     //
            "https://parceiro.example.com/webhooks/dinie"

            console.log(endpoint.events);  // ["customer.active",
            "credit_offer.available", "loan.*"]

            console.log(endpoint.status);  // "active"
        - lang: Ruby
          source: >
            require "dinie"


            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )


            # Retrieve a webhook endpoint

            endpoint = client.webhooks.retrieve_endpoint(
              "we_550e8400e29b41d4a716446655440000"
            )


            puts endpoint.url     #
            "https://parceiro.example.com/webhooks/dinie"

            puts endpoint.events  # ["customer.active",
            "credit_offer.available", "loan.*"]

            puts endpoint.status  # "active"
    patch:
      operationId: updateWebhookEndpoint
      summary: Update a webhook endpoint
      description: >
        Updates the configuration of a webhook endpoint. Allows changing the
        destination URL,

        the list of subscribed events, the description, and the status
        (`active`/`disabled`). Use

        `disabled` to temporarily pause deliveries without deleting the
        endpoint. Only

        the submitted fields are updated.
      tags:
        - Webhooks
      parameters:
        - $ref: '#/components/parameters/WebhookEndpointId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWebhookEndpointRequest'
            example:
              events:
                - customer.*
                - loan.*
              status: active
      responses:
        '200':
          description: Webhook endpoint updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpoint'
              example:
                id: we_550e8400e29b41d4a716446655440000
                url: https://parceiro.example.com/webhooks/dinie
                events:
                  - customer.*
                  - loan.*
                description: Webhook de produção
                status: active
                created_at: '2026-03-04T10:00:00Z'
                updated_at: '2026-03-05T09:00:00Z'
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
                malformed_body:
                  summary: Request body is not valid JSON
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: Request body is not valid JSON
                    code: malformed_body
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                webhook_endpoint_not_found:
                  summary: >-
                    Endpoint ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Endpoint ID does not exist or does not belong to this
                      partner
                    code: webhook_endpoint_not_found
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_url:
                  summary: '`url` is not a valid HTTPS URL'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`url` is not a valid HTTPS URL'
                    code: invalid_url
                invalid_events:
                  summary: '`events` contains unrecognized event types'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`events` contains unrecognized event types'
                    code: invalid_events
                invalid_status:
                  summary: '`status` is not `active` or `disabled`'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`status` is not `active` or `disabled`'
                    code: invalid_status
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl -X PATCH
            https://api.dinie.com.br/v3/webhooks/endpoints/we_550e8400e29b41d4a716446655440000
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -d '{
                "events": ["customer.*", "loan.*"],
                "status": "active"
              }'
        - lang: Python
          source: |
            from dinie import Dinie

            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )

            # Update webhook endpoint events and status
            endpoint = client.webhooks.update_endpoint(
                "we_550e8400e29b41d4a716446655440000",
                events=["customer.*", "loan.*"],
                status="active"
            )

            print(endpoint.events)  # ["customer.*", "loan.*"]
            print(endpoint.status)  # "active"
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Update webhook endpoint events and status
            const endpoint = await client.webhooks.updateEndpoint(
              "we_550e8400e29b41d4a716446655440000",
              {
                events: ["customer.*", "loan.*"],
                status: "active",
              }
            );

            console.log(endpoint.events);  // ["customer.*", "loan.*"]
            console.log(endpoint.status);  // "active"
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Update webhook endpoint events and status
            endpoint = client.webhooks.update_endpoint(
              "we_550e8400e29b41d4a716446655440000",
              events: ["customer.*", "loan.*"],
              status: "active"
            )

            puts endpoint.events  # ["customer.*", "loan.*"]
            puts endpoint.status  # "active"
    delete:
      operationId: deleteWebhookEndpoint
      summary: Delete a webhook endpoint
      description: Deletes a webhook endpoint. Stops all deliveries.
      tags:
        - Webhooks
      parameters:
        - $ref: '#/components/parameters/WebhookEndpointId'
      responses:
        '204':
          description: Webhook endpoint deleted (empty body)
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                webhook_endpoint_not_found:
                  summary: >-
                    Endpoint ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Endpoint ID does not exist or does not belong to this
                      partner
                    code: webhook_endpoint_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl -X DELETE
            https://api.dinie.com.br/v3/webhooks/endpoints/we_550e8400e29b41d4a716446655440000
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN"
        - lang: Python
          source: >
            from dinie import Dinie


            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )


            # Delete a webhook endpoint

            client.webhooks.delete_endpoint("we_550e8400e29b41d4a716446655440000")

            # 204 No Content -- endpoint deleted, deliveries stopped
        - lang: Node.js
          source: |
            const { Dinie } = require("dinie");

            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });

            // Delete a webhook endpoint
            await client.webhooks.deleteEndpoint(
              "we_550e8400e29b41d4a716446655440000"
            );
            // 204 No Content -- endpoint deleted, deliveries stopped
        - lang: Ruby
          source: >
            require "dinie"


            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )


            # Delete a webhook endpoint

            client.webhooks.delete_endpoint("we_550e8400e29b41d4a716446655440000")

            # 204 No Content -- endpoint deleted, deliveries stopped
  /webhooks/endpoints/{webhook_endpoint_id}/secret/rotate:
    post:
      operationId: rotateWebhookSecret
      summary: Rotate the signing secret
      description: >
        Rotates the HMAC signing secret of the endpoint. A new secret is
        generated and

        returned in the response. The previous secret remains valid during the
        grace period

        defined by `expire_current_in` (default: 3600 seconds). During this
        period,

        deliveries include signatures with both secrets, allowing a gradual
        migration

        in your system without losing events.
      tags:
        - Webhooks
      parameters:
        - $ref: '#/components/parameters/WebhookEndpointId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                expire_current_in:
                  type: integer
                  description: >-
                    Seconds until the current secret expires. Default 3600. Max
                    86400.
                  default: 3600
                  minimum: 0
                  maximum: 86400
            example:
              expire_current_in: 3600
      responses:
        '200':
          description: Secret rotated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSecretRotation'
              example:
                id: we_550e8400e29b41d4a716446655440000
                secret: whsec_novo1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8
                previous_secret_expires_at: '2026-03-04T11:00:00Z'
        '400':
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_content_type:
                  summary: '`Content-Type` is not `application/json`'
                  value:
                    type: https://docs.dinie.com.br/errors/invalid-request
                    title: Invalid Request
                    status: 400
                    detail: '`Content-Type` is not `application/json`'
                    code: invalid_content_type
        '401':
          description: Authentication failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                missing_token:
                  summary: Authorization header is missing
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Authorization header is missing
                    code: missing_token
                invalid_token:
                  summary: Bearer token is invalid or malformed
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token is invalid or malformed
                    code: invalid_token
                token_expired:
                  summary: Bearer token has expired
                  value:
                    type: https://docs.dinie.com.br/errors/authentication-failed
                    title: Authentication Failed
                    status: 401
                    detail: Bearer token has expired
                    code: token_expired
        '404':
          description: Resource not found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                webhook_endpoint_not_found:
                  summary: >-
                    Endpoint ID does not exist or does not belong to this
                    partner
                  value:
                    type: https://docs.dinie.com.br/errors/not-found
                    title: Not Found
                    status: 404
                    detail: >-
                      Endpoint ID does not exist or does not belong to this
                      partner
                    code: webhook_endpoint_not_found
        '422':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
              examples:
                invalid_expire_current_in:
                  summary: '`expire_current_in` is outside the 0–86400 range'
                  value:
                    type: https://docs.dinie.com.br/errors/validation-failed
                    title: Validation Failed
                    status: 422
                    detail: '`expire_current_in` is outside the 0–86400 range'
                    code: invalid_expire_current_in
        '429':
          $ref: '#/components/responses/RateLimited'
          description: Rate limit exceeded
        '500':
          $ref: '#/components/responses/InternalError'
          description: Internal server error
      x-codeSamples:
        - lang: curl
          source: >
            curl -X POST
            https://api.dinie.com.br/v3/webhooks/endpoints/we_550e8400e29b41d4a716446655440000/secret/rotate
            \
              -H "Authorization: Bearer $DINIE_API_TOKEN" \
              -H "Content-Type: application/json" \
              -d '{"expire_current_in": 3600}'
        - lang: Python
          source: >
            from dinie import Dinie


            client = Dinie(
                client_id="dinie_ci_abc123",
                client_secret="dinie_cs_live_xyz789"
            )


            # Rotate the webhook signing secret

            rotation = client.webhooks.rotate_secret(
                "we_550e8400e29b41d4a716446655440000",
                expire_current_in=3600  # previous secret valid for 1 more hour
            )


            print(rotation.secret)                       # "whsec_novo1b2c3..."

            print(rotation.previous_secret_expires_at)   #
            "2026-03-04T11:00:00Z"
        - lang: Node.js
          source: >
            const { Dinie } = require("dinie");


            const client = new Dinie({
              clientId: "dinie_ci_abc123",
              clientSecret: "dinie_cs_live_xyz789",
            });


            // Rotate the webhook signing secret

            const rotation = await client.webhooks.rotateSecret(
              "we_550e8400e29b41d4a716446655440000",
              { expireCurrentIn: 3600 }  // previous secret valid for 1 more hour
            );


            console.log(rotation.secret);                       //
            "whsec_novo1b2c3..."

            console.log(rotation.previousSecretExpiresAt);      //
            "2026-03-04T11:00:00Z"
        - lang: Ruby
          source: |
            require "dinie"

            client = Dinie::Client.new(
              client_id: "dinie_ci_abc123",
              client_secret: "dinie_cs_live_xyz789"
            )

            # Rotate the webhook signing secret
            rotation = client.webhooks.rotate_secret(
              "we_550e8400e29b41d4a716446655440000",
              expire_current_in: 3600  # previous secret valid for 1 more hour
            )

            puts rotation.secret                       # "whsec_novo1b2c3..."
            puts rotation.previous_secret_expires_at   # "2026-03-04T11:00:00Z"
webhooks:
  customer.created:
    post:
      operationId: onCustomerCreated
      summary: Customer created
      description: >
        Fires immediately after a new customer is registered via `POST
        /customers`.

        Includes the customer's full registration data with `pending_kyc`
        status.

        Use it to confirm registration receipt and start the KYC document
        collection flow.
      tags:
        - Customers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_CustomerCreated'
            example:
              type: customer.created
              timestamp: '2026-03-04T10:00:00Z'
              data:
                id: cust_550e8400e29b41d4a716446655440000
                status: pending_kyc
                cpf: 123.456.789-00
                cnpj: 12.345.678/0001-90
                name: João Silva
                email: joao@example.com
                phone: '+5511999999999'
                trading_name: Loja do João
                external_id: partner-ref-123
      responses:
        '200':
          description: Event received
  customer.under_review:
    post:
      operationId: onCustomerUnderReview
      summary: Customer under review
      description: >
        Fires when all required KYC documents have been submitted and the credit
        review

        is started by Dinie. Includes the customer ID and `under_review` status.

        Use it to update the status in your system and inform the customer that
        the review is in progress.
      tags:
        - Customers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_CustomerStatus'
            example:
              type: customer.under_review
              timestamp: '2026-03-04T12:00:00Z'
              data:
                id: cust_550e8400e29b41d4a716446655440000
                status: under_review
                external_id: partner-ref-123
      responses:
        '200':
          description: Event received
  customer.kyc_updated:
    post:
      operationId: onCustomerKycUpdated
      summary: Customer KYC updated
      description: >
        Fires when any KYC requirement changes status (approved, rejected, or

        pending correction). Includes the full `kyc` array with the updated
        status of

        each item. Use it to identify rejected documents and request
        resubmission from the customer

        via `PATCH /customers/{id}` or `POST /customers/{id}/documents`.
      tags:
        - Customers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_CustomerKycUpdated'
            example:
              type: customer.kyc_updated
              timestamp: '2026-03-04T12:30:00Z'
              data:
                id: cust_550e8400e29b41d4a716446655440000
                status: pending_kyc
                external_id: partner-ref-123
                kyc:
                  - kind: document
                    type: ccmei
                    description: Certificado MEI
                    status: approved
                    message: null
                    uploaded_at: '2026-03-04T11:00:00Z'
                  - kind: document
                    type: selfie
                    description: Selfie
                    status: pending
                    message: null
                    uploaded_at: null
      responses:
        '200':
          description: Event received
  customer.active:
    post:
      operationId: onCustomerActive
      summary: Customer active
      description: >
        Fires when the customer is fully verified (KYC approved) and eligible to

        receive credit offers. Includes the customer ID and `active` status.
        This is the

        time to query `GET /customers/{id}/credit-offers` to check for available

        pre-approved offers.
      tags:
        - Customers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_CustomerStatus'
            example:
              type: customer.active
              timestamp: '2026-03-04T14:00:00Z'
              data:
                id: cust_550e8400e29b41d4a716446655440000
                status: active
                external_id: partner-ref-123
      responses:
        '200':
          description: Event received
  credit_offer.available:
    post:
      operationId: onCreditOfferAvailable
      summary: Credit offer available
      description: >
        Fires when Dinie generates a new pre-approved credit offer for the
        customer.

        Includes approved amount, interest rate, installments, and offer
        expiration date.

        Use it to notify the customer about credit availability and start the
        simulation flow

        via `POST /credit-offers/{id}/simulations`.
      tags:
        - Credit Offers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_CreditOffer'
            example:
              type: credit_offer.available
              timestamp: '2026-03-04T15:00:00Z'
              data:
                id: co_550e8400e29b41d4a716446655440000
                customer_id: cust_550e8400e29b41d4a716446655440000
                status: available
                approved_amount: '50000.00'
                min_amount: '1000.00'
                interest_rate: 3.5
                installments: 12
                due_date_rule: null
                valid_until: '2026-04-01T23:59:59Z'
      responses:
        '200':
          description: Event received
  credit_offer.expired:
    post:
      operationId: onCreditOfferExpired
      summary: Credit offer expired
      description: >
        Fires when a credit offer expires after exceeding its expiration date

        (`valid_until`). Includes the full offer data with `expired` status.

        Use it to remove the offer from the customer interface. New offers may
        be generated

        in the future via `credit_offer.available`.
      tags:
        - Credit Offers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_CreditOffer'
            example:
              type: credit_offer.expired
              timestamp: '2026-04-02T00:00:00Z'
              data:
                id: co_660e8400e29b41d4a716446655440001
                customer_id: cust_550e8400e29b41d4a716446655440000
                status: expired
                approved_amount: '30000.00'
                min_amount: '1000.00'
                interest_rate: 3.5
                installments: 12
                due_date_rule: null
                valid_until: '2026-04-01T23:59:59Z'
      responses:
        '200':
          description: Event received
  loan.created:
    post:
      operationId: onLoanCreated
      summary: Loan created
      description: >
        Fires when the loan is created via `POST /loans` from an accepted offer.

        Includes the loan, offer, and customer IDs, as well as the requested
        amount and number of installments.

        The loan starts with `processing` status. Use it to register the loan in
        your system.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanCreated'
            example:
              type: loan.created
              timestamp: '2026-03-04T16:00:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                credit_offer_id: co_550e8400e29b41d4a716446655440000
                customer_id: cust_550e8400e29b41d4a716446655440000
                status: processing
                requested_amount: '25000.00'
                number_of_installments: 12
      responses:
        '200':
          description: Event received
  loan.contract_generated:
    post:
      operationId: onLoanContractGenerated
      summary: Loan contract generated
      description: >
        Fires when the CCB (Cedula de Credito Bancario) contract is generated by
        Dinie.

        Includes the ClickSign `signing_url` for digital contract signing.

        Use it to present the signing link to the customer in your flow.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanContract'
            example:
              type: loan.contract_generated
              timestamp: '2026-03-04T16:30:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: contract_generated
                signing_url: https://clicksign.com/sign/abc123
      responses:
        '200':
          description: Event received
  loan.awaiting_signatures:
    post:
      operationId: onLoanAwaitingSignatures
      summary: Loan awaiting signatures
      description: >
        Fires when the CCB contract is sent to ClickSign and awaits the
        customer's signature.

        Includes the updated `signing_url`. Use it to resend the signing link to
        the customer

        or display a reminder if the signature has not yet been completed.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanContract'
            example:
              type: loan.awaiting_signatures
              timestamp: '2026-03-04T17:00:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: awaiting_signatures
                signing_url: https://clicksign.com/sign/abc123
      responses:
        '200':
          description: Event received
  loan.signed:
    post:
      operationId: onLoanSigned
      summary: Loan signed
      description: >
        Fires when the CCB contract is fully signed by all signatories on
        ClickSign.

        Includes the registered contract `ccb_number`. The next step is
        automatic disbursement.

        Use it to confirm to the customer that the contract has been
        successfully signed.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanSigned'
            example:
              type: loan.signed
              timestamp: '2026-03-05T10:00:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: signed
                ccb_number: CCB-2026-001234
      responses:
        '200':
          description: Event received
  loan.disbursing:
    post:
      operationId: onLoanDisbursing
      summary: Loan disbursing
      description: >
        Fires when Dinie initiates the fund transfer to the customer's account.

        Includes the disbursement method used (e.g., `pix`). The transfer may
        take

        a few minutes. Use it to inform the customer that the amount is being
        transferred.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanDisbursing'
            example:
              type: loan.disbursing
              timestamp: '2026-03-05T11:00:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: disbursing
                disbursement_method: pix
      responses:
        '200':
          description: Event received
  loan.active:
    post:
      operationId: onLoanActive
      summary: Loan active
      description: >
        Fires when the disbursement is confirmed and the loan enters the
        repayment phase.

        Includes the requested amount (`requested_amount`) and the net amount
        received (`net_amount`).

        Use it to confirm to the customer that the funds have been credited and
        present the installment schedule.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanActive'
            example:
              type: loan.active
              timestamp: '2026-03-05T12:00:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: active
                requested_amount: '25000.00'
                net_amount: '24250.00'
      responses:
        '200':
          description: Event received
  loan.payment_received:
    post:
      operationId: onLoanPaymentReceived
      summary: Loan payment received
      description: >
        Fires when an installment payment is recorded for the loan. Includes the
        amount

        paid, payment date, and corresponding installment number. Use it to
        update the

        outstanding balance in your system and notify the customer about the
        payment confirmation.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanPaymentReceived'
            example:
              type: loan.payment_received
              timestamp: '2026-04-03T10:00:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: active
                payment:
                  amount: '2500.00'
                  paid_at: '2026-04-03T10:00:00Z'
                  installment_number: 1
      responses:
        '200':
          description: Event received
  loan.finished:
    post:
      operationId: onLoanFinished
      summary: Loan finished
      description: >
        Fires when all loan installments are paid off and the contract is
        closed.

        Includes the loan ID and `finished` status. Use it to mark the loan as

        completed in your system and check if new credit offers are available.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanStatus'
            example:
              type: loan.finished
              timestamp: '2026-10-15T14:00:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: finished
      responses:
        '200':
          description: Event received
  loan.cancelled:
    post:
      operationId: onLoanCancelled
      summary: Loan cancelled
      description: >
        Fires when the loan is cancelled before disbursement is completed.
        Includes the loan ID

        and `cancelled` status. Use it to update the status in your system and

        inform the customer. The original credit offer may still be available
        for a new request.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanStatus'
            example:
              type: loan.cancelled
              timestamp: '2026-04-02T11:30:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: cancelled
      responses:
        '200':
          description: Event received
  loan.error:
    post:
      operationId: onLoanError
      summary: Loan error
      description: >
        Fires when an unrecoverable error occurs in the loan, such as a
        disbursement failure

        or contract generation error. Includes the error code and message in the
        `error` field.

        Use it to alert your team, log the issue, and inform the customer about
        the situation.
      tags:
        - Loans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEvent_LoanStatus'
            example:
              type: loan.error
              timestamp: '2026-04-02T09:15:00Z'
              data:
                id: ln_550e8400e29b41d4a716446655440001
                status: error
                error:
                  code: disbursement_failed
                  message: Falha na transferência bancária
      responses:
        '200':
          description: Event received
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >
        JWT token obtained via OAuth2 Client Credentials. Send `POST
        /auth/token`

        with your credentials (`client_id` and `client_secret`) in the

        `Authorization: Basic base64(client_id:client_secret)` header to receive
        an

        access token. Include the token in all requests:

        `Authorization: Bearer <token>`. The token expires in 1 hour (3600s).


        Prefixes: `dinie_cs_live_` (production), `dinie_cs_test_` (sandbox).

        The returned token is prefixed with `dinie_at_`.
    oauth2:
      type: oauth2
      description: |
        OAuth2 Client Credentials flow for obtaining access tokens.
        Use `client_id` and `client_secret` to authenticate.
      flows:
        clientCredentials:
          tokenUrl: /v3/auth/token
          scopes: {}
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: Unique string for idempotent POST requests. Cached for 24 hours.
      schema:
        type: string
    StartingAfter:
      name: starting_after
      in: query
      description: Prefixed ID of the last item from the previous page.
      schema:
        type: string
    Limit:
      name: limit
      in: query
      description: 'Number of items to return. Min: 1, Max: 100.'
      schema:
        type: integer
        default: 25
        minimum: 1
        maximum: 100
    CustomerId:
      name: customer_id
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/CustomerId'
    CreditOfferId:
      name: credit_offer_id
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/CreditOfferId'
    LoanId:
      name: loan_id
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/LoanId'
    WebhookEndpointId:
      name: webhook_endpoint_id
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/WebhookEndpointId'
  responses:
    BadRequest:
      description: Bad request
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/invalid-request
            title: Invalid Request
            status: 400
            detail: Request body is not valid JSON.
    Unauthorized:
      description: Authentication failed
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/authentication-failed
            title: Authentication Failed
            status: 401
            detail: Bearer token is invalid or has expired.
    Forbidden:
      description: Forbidden
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/forbidden
            title: Forbidden
            status: 403
            detail: You do not have permission to perform this action.
    NotFound:
      description: Resource not found
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/not-found
            title: Not Found
            status: 404
            detail: The requested resource does not exist.
    Conflict:
      description: Conflict
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/conflict
            title: Conflict
            status: 409
            detail: Resource already exists.
    ValidationFailed:
      description: Validation failed
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/validation-failed
            title: Validation Failed
            status: 422
            detail: One or more fields failed validation.
            errors:
              - param: cpf
                detail: CPF fails check-digit validation.
                code: invalid_cpf
    RateLimited:
      description: Rate limit exceeded
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds until the rate limit resets
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/rate-limit-exceeded
            title: Rate Limit Exceeded
            status: 429
            detail: Too many requests. Retry after 30 seconds.
    InternalError:
      description: Internal server error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: https://docs.dinie.com.br/errors/internal
            title: Internal Error
            status: 500
            detail: An unexpected error occurred.
  schemas:
    CustomerId:
      type: string
      pattern: ^cust_[0-9a-f]{32}$
      example: cust_550e8400e29b41d4a716446655440000
    CreditOfferId:
      type: string
      pattern: ^co_[0-9a-f]{32}$
      example: co_550e8400e29b41d4a716446655440000
    LoanId:
      type: string
      pattern: ^ln_[0-9a-f]{32}$
      example: ln_550e8400e29b41d4a716446655440000
    TransactionId:
      type: string
      pattern: ^tx_[0-9a-f]{32}$
      example: tx_550e8400e29b41d4a716446655440000
    DocumentId:
      type: string
      pattern: ^doc_[0-9a-f]{32}$
      example: doc_550e8400e29b41d4a716446655440000
    SimulationId:
      type: string
      pattern: ^sim_[0-9a-f]{32}$
      example: sim_550e8400e29b41d4a716446655440000
    WebhookEndpointId:
      type: string
      pattern: ^we_[0-9a-f]{32}$
      example: we_550e8400e29b41d4a716446655440000
    ApiClientId:
      type: string
      pattern: ^dinie_ci_[0-9a-f]{32}$
      example: dinie_ci_550e8400e29b41d4a716446655440000
    Money:
      type: string
      pattern: ^\d+\.\d{2}$
      description: Decimal encoded as a string with exactly 2 decimal places (BRL).
      example: '25000.00'
    ProblemDetail:
      type: object
      description: Problem Details per RFC 9457
      required:
        - type
        - title
        - status
        - detail
      properties:
        type:
          type: string
          format: uri
          description: URI identifying the error type
        title:
          type: string
          description: Short, human-readable summary of the problem type
        status:
          type: integer
          description: HTTP status code
        detail:
          type: string
          description: Human-readable explanation specific to this occurrence
        instance:
          type: string
          format: uri
          description: URI identifying this specific occurrence
        code:
          type: string
          description: Machine-readable subtype code
        param:
          type: string
          description: The request parameter that caused the error
        errors:
          type: array
          description: Field-level validation errors
          items:
            $ref: '#/components/schemas/FieldError'
    FieldError:
      type: object
      required:
        - param
        - detail
      properties:
        param:
          type: string
        detail:
          type: string
        code:
          type: string
    TokenResponse:
      type: object
      required:
        - access_token
        - token_type
        - expires_in
      properties:
        access_token:
          type: string
          description: JWT access token
          example: dinie_at_eyJhbGciOiJIUzI1NiJ9...
        token_type:
          type: string
          enum:
            - bearer
        expires_in:
          type: integer
          description: Token lifetime in seconds
          example: 3600
    CreateCredentialRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          description: Human-readable label for this key
          example: Production Key
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
          description: Optional expiration date. Null = never expires.
          example: '2027-03-04T00:00:00Z'
    Credential:
      type: object
      required:
        - id
        - client_id
        - name
        - status
        - expires_at
        - created_at
        - updated_at
        - last_used_at
      properties:
        id:
          $ref: '#/components/schemas/ApiClientId'
        client_id:
          $ref: '#/components/schemas/ApiClientId'
        name:
          type: string
          example: Production Key
        status:
          type: string
          enum:
            - active
            - revoked
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        last_used_at:
          type:
            - string
            - 'null'
          format: date-time
    CredentialWithSecret:
      description: >-
        Returned only at creation. The `client_secret` cannot be retrieved
        again.
      allOf:
        - $ref: '#/components/schemas/Credential'
        - type: object
          required:
            - client_secret
          properties:
            client_secret:
              type: string
              description: Store securely -- shown only once.
              example: dinie_cs_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    CreateCustomerRequest:
      type: object
      required:
        - cpf
      properties:
        cpf:
          type: string
          description: Customer CPF (required)
          example: 123.456.789-00
        cnpj:
          type:
            - string
            - 'null'
          description: Company CNPJ
          example: 12.345.678/0001-90
        name:
          type: string
          example: Joao Silva
        email:
          type: string
          format: email
          example: joao@example.com
        phone:
          type: string
          description: E.164 format
          example: '+5511999999999'
        trading_name:
          type: string
          example: Loja do Joao
        external_id:
          type: string
          description: Partner external reference for this customer
          example: partner-ref-123
    UpdateCustomerRequest:
      type: object
      properties:
        email:
          type: string
          format: email
        phone:
          type: string
        name:
          type: string
        cnpj:
          type: string
        trading_name:
          type: string
    Customer:
      type: object
      required:
        - id
        - status
        - cpf
        - cnpj
        - name
        - email
        - phone
        - trading_name
        - external_id
        - kyc
        - created_at
        - updated_at
      properties:
        id:
          $ref: '#/components/schemas/CustomerId'
        status:
          type: string
          enum:
            - pending_kyc
            - under_review
            - active
          x-enumDescriptions:
            pending_kyc: >-
              Customer registered, but KYC documents/biometrics not yet
              submitted or under review
            under_review: >-
              All required KYC items submitted; Dinie's compliance team is
              reviewing
            active: KYC approved; customer is eligible to receive credit offers
        cpf:
          type: string
          example: 123.456.789-00
        cnpj:
          type:
            - string
            - 'null'
          example: 12.345.678/0001-90
        name:
          type: string
          example: Joao Silva
        email:
          type: string
          format: email
          example: joao@example.com
        phone:
          type: string
          example: '+5511999999999'
        trading_name:
          type:
            - string
            - 'null'
          example: Loja do Joao
        external_id:
          type:
            - string
            - 'null'
          example: partner-ref-123
        kyc:
          type: array
          items:
            $ref: '#/components/schemas/KycItem'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    KycItem:
      type: object
      required:
        - kind
        - type
        - description
        - status
        - message
        - uploaded_at
      properties:
        kind:
          type: string
          enum:
            - document
            - data
          description: >-
            `document` for document submissions, `data` for data field
            corrections
        type:
          type: string
          description: Document type key (e.g., `ccmei`, `selfie`, `identity_card_front`)
          example: ccmei
        description:
          type: string
          description: Human-readable label
          example: Certificado MEI
        status:
          type: string
          enum:
            - pending
            - submitted
            - approved
            - pending_resubmission
            - pending_correction
          x-enumDescriptions:
            pending: Awaiting submission by the customer
            submitted: Document submitted, awaiting review
            approved: Document reviewed and approved
            pending_resubmission: Document rejected; customer must resubmit
            pending_correction: Data field needs correction by the customer
        message:
          type:
            - string
            - 'null'
          description: Present when rejected — from the review feedback
        uploaded_at:
          type:
            - string
            - 'null'
          format: date-time
    Document:
      type: object
      required:
        - id
        - type
        - status
        - uploaded_at
        - created_at
        - updated_at
      properties:
        id:
          $ref: '#/components/schemas/DocumentId'
        type:
          type: string
          example: ccmei
          description: Document type
        status:
          type: string
          enum:
            - submitted
            - approved
            - rejected
          description: Document status
        uploaded_at:
          type: string
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    BiometricsSession:
      type: object
      required:
        - session_url
        - expires_at
      properties:
        session_url:
          type: string
          format: uri
          description: URL for the partner to embed in their flow (webview or redirect)
          example: https://biometrics.dinie.com.br/session/...
        expires_at:
          type: string
          format: date-time
          example: '2026-03-03T16:00:00Z'
    CreditOffer:
      type: object
      required:
        - id
        - customer_id
        - status
        - approved_amount
        - min_amount
        - interest_rate
        - installments
        - valid_until
        - created_at
        - updated_at
      properties:
        id:
          $ref: '#/components/schemas/CreditOfferId'
        customer_id:
          $ref: '#/components/schemas/CustomerId'
        status:
          type: string
          enum:
            - available
            - accepted
            - expired
          x-enumDescriptions:
            available: Offer is active and can be accepted by the customer
            accepted: Customer accepted the offer and a loan was created
            expired: Offer passed the valid_until date without being accepted
        approved_amount:
          $ref: '#/components/schemas/Money'
        min_amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Minimum withdrawal amount
          example: '1000.00'
        interest_rate:
          type: number
          description: Monthly interest rate percentage
          example: 3.5
        installments:
          type: integer
          description: >-
            Number of installments. When the product supports a range, this
            field is replaced by min_installments/max_installments
          example: 12
        due_date_rule:
          type:
            - string
            - 'null'
          description: Due date rule for installments. Pending Core implementation.
        valid_until:
          type: string
          format: date-time
          example: '2026-04-01T23:59:59Z'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    CreateSimulationRequest:
      type: object
      required:
        - requested_amount
        - installment_count
      properties:
        requested_amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Requested loan amount
          example: '25000.00'
        installment_count:
          type: integer
          minimum: 1
          description: Number of installments for the simulation
          example: 12
    Simulation:
      type: object
      required:
        - id
        - credit_offer_id
        - requested_amount
        - amount
        - interest_amount
        - fees_amount
        - iof_amount
        - total_loan_amount
        - interest_percentage
        - cet_percentage
        - number_of_installments
        - installments_value
        - first_due_date
        - created_at
      properties:
        id:
          $ref: '#/components/schemas/SimulationId'
        credit_offer_id:
          $ref: '#/components/schemas/CreditOfferId'
        requested_amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Amount requested by the partner
          example: '25000.00'
        amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Net amount to be received by the customer
          example: '24250.00'
        interest_amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Total interest amount
          example: '2750.00'
        fees_amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Total fees amount
          example: '300.00'
        iof_amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: IOF tax amount
          example: '450.00'
        total_loan_amount:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Total loan amount (principal + interest + fees + IOF)
          example: '27500.00'
        interest_percentage:
          type: number
          description: Monthly interest rate (percentage)
          example: 3.5
        cet_percentage:
          type: number
          description: Total effective cost (annual percentage)
          example: 4.12
        number_of_installments:
          type: integer
          description: Number of installments
          example: 12
        installments_value:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Amount per installment
          example: '2291.67'
        first_due_date:
          type: string
          format: date
          description: Due date of the first installment
          example: '2026-04-03'
        created_at:
          type: string
          format: date-time
    CreateLoanRequest:
      type: object
      required:
        - credit_offer_id
        - simulation_id
        - installments
        - installments_value
        - first_due_date
      properties:
        credit_offer_id:
          $ref: '#/components/schemas/CreditOfferId'
        simulation_id:
          $ref: '#/components/schemas/SimulationId'
        installments:
          type: integer
          minimum: 1
          description: Number of installments
          example: 12
        installments_value:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Amount per installment
          example: '2291.67'
        first_due_date:
          type: string
          format: date
          description: Due date of the first installment
          example: '2026-04-03'
    Loan:
      type: object
      required:
        - id
        - credit_offer_id
        - simulation_id
        - customer_id
        - status
        - requested_amount
        - net_amount
        - iof
        - service_fee
        - interest_rate
        - cet
        - total_amount
        - installments_value
        - first_due_date
        - number_of_installments
        - ccb_number
        - disbursement_method
        - signing_url
        - created_at
        - updated_at
      properties:
        id:
          $ref: '#/components/schemas/LoanId'
        credit_offer_id:
          $ref: '#/components/schemas/CreditOfferId'
        simulation_id:
          $ref: '#/components/schemas/SimulationId'
        customer_id:
          $ref: '#/components/schemas/CustomerId'
        status:
          type: string
          enum:
            - processing
            - contract_generated
            - awaiting_signatures
            - signed
            - disbursing
            - active
            - finished
            - cancelled
            - error
          x-enumDescriptions:
            processing: Loan request received, credit analysis in progress
            contract_generated: CCB contract generated, ready for signatures
            awaiting_signatures: Contract sent to customer for electronic signature
            signed: Customer signed the contract, awaiting disbursement
            disbursing: Funds are being transferred to the customer
            active: Loan disbursed, installments are being collected
            finished: All installments paid, loan completed
            cancelled: Loan cancelled before disbursement
            error: An error occurred during processing
        requested_amount:
          $ref: '#/components/schemas/Money'
        net_amount:
          type:
            - string
            - 'null'
          pattern: ^\d+\.\d{2}$
          description: Net amount after fees. Null until calculated.
        iof:
          type:
            - string
            - 'null'
          pattern: ^\d+\.\d{2}$
        service_fee:
          type:
            - string
            - 'null'
          pattern: ^\d+\.\d{2}$
        interest_rate:
          type:
            - number
            - 'null'
          description: Monthly interest rate (percentage)
        cet:
          type:
            - number
            - 'null'
          description: Total effective cost (annual percentage)
        total_amount:
          $ref: '#/components/schemas/Money'
        installments_value:
          type: string
          pattern: ^\d+\.\d{2}$
          description: Amount per installment
          example: '2291.67'
        first_due_date:
          type: string
          format: date
          description: Due date of the first installment
          example: '2026-04-03'
        number_of_installments:
          type: integer
        ccb_number:
          type:
            - string
            - 'null'
          description: CCB contract number. Null until the contract is generated.
        disbursement_method:
          type:
            - string
            - 'null'
          description: Disbursement method (e.g., `pix`). Null until disbursement.
        signing_url:
          type:
            - string
            - 'null'
          format: uri
          description: >-
            ClickSign widget URL. Present only during contract_generated and
            awaiting_signatures.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    Transaction:
      type: object
      required:
        - id
        - loan_id
        - type
        - due_date
        - status
        - amount_due
        - amount_paid
        - amount_remaining
        - principal
        - interest
        - fees
        - days_overdue
        - paid_at
        - created_at
        - updated_at
      properties:
        id:
          $ref: '#/components/schemas/TransactionId'
        loan_id:
          $ref: '#/components/schemas/LoanId'
        type:
          type: string
          enum:
            - installment
        due_date:
          type: string
          format: date
          example: '2026-04-03'
        status:
          type: string
          enum:
            - pending
            - paid
            - overdue
            - partially_paid
          x-enumDescriptions:
            pending: Payment not yet due or awaiting payment
            paid: Full payment received
            overdue: Payment overdue without full settlement
            partially_paid: Partial payment received
        amount_due:
          $ref: '#/components/schemas/Money'
        amount_paid:
          $ref: '#/components/schemas/Money'
        amount_remaining:
          $ref: '#/components/schemas/Money'
        principal:
          $ref: '#/components/schemas/Money'
        interest:
          $ref: '#/components/schemas/Money'
        fees:
          $ref: '#/components/schemas/Money'
        days_overdue:
          type: integer
          minimum: 0
        paid_at:
          type:
            - string
            - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    CreateWebhookEndpointRequest:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          format: uri
          description: HTTPS URL to receive webhook deliveries
          example: https://partner.example.com/webhooks/dinie
        events:
          type: array
          items:
            type: string
          description: >-
            Event types to subscribe to. Supports wildcards `*` (e.g.,
            `loan.*`). Empty or omitted = all events.
          example:
            - customer.active
            - credit_offer.available
            - loan.*
        description:
          type: string
          description: Optional human-readable label
          example: Production webhook
    UpdateWebhookEndpointRequest:
      type: object
      properties:
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        description:
          type: string
        status:
          type: string
          enum:
            - active
            - disabled
    WebhookEndpoint:
      type: object
      required:
        - id
        - url
        - events
        - description
        - status
        - created_at
        - updated_at
      properties:
        id:
          $ref: '#/components/schemas/WebhookEndpointId'
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        description:
          type:
            - string
            - 'null'
        status:
          type: string
          enum:
            - active
            - disabled
          x-enumDescriptions:
            active: Endpoint is receiving webhook deliveries
            disabled: Endpoint is paused; no webhooks will be sent
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    WebhookEndpointWithSecret:
      description: Returned only on creation. The `secret` cannot be retrieved again.
      allOf:
        - $ref: '#/components/schemas/WebhookEndpoint'
        - type: object
          required:
            - secret
          properties:
            secret:
              type: string
              description: >-
                HMAC signing secret (prefix `whsec_`). Store securely -- shown
                only once.
              example: whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    WebhookSecretRotation:
      type: object
      required:
        - id
        - secret
        - previous_secret_expires_at
      properties:
        id:
          $ref: '#/components/schemas/WebhookEndpointId'
        secret:
          type: string
          description: New HMAC signing secret
          example: whsec_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
        previous_secret_expires_at:
          type: string
          format: date-time
          description: When the old secret stops being included in signatures
    WebhookEventBase:
      type: object
      required:
        - type
        - timestamp
        - data
      description: |
        Standard Webhooks envelope. Delivered with the headers:
        `webhook-id`, `webhook-timestamp`, `webhook-signature`.
      properties:
        type:
          type: string
          description: Event type identifier
        timestamp:
          type: string
          format: date-time
          description: When the event occurred
    WebhookEvent_CustomerCreated:
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - customer.created
            data:
              type: object
              required:
                - id
                - status
                - cpf
                - name
                - email
                - phone
                - external_id
              properties:
                id:
                  $ref: '#/components/schemas/CustomerId'
                status:
                  type: string
                  enum:
                    - pending_kyc
                cpf:
                  type: string
                cnpj:
                  type:
                    - string
                    - 'null'
                name:
                  type: string
                email:
                  type: string
                phone:
                  type: string
                trading_name:
                  type:
                    - string
                    - 'null'
                external_id:
                  type:
                    - string
                    - 'null'
      description: Event fired when a new customer is registered.
    WebhookEvent_CustomerStatus:
      description: Used for `customer.under_review` and `customer.active` events.
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - customer.under_review
                - customer.active
            data:
              type: object
              required:
                - id
                - status
                - external_id
              properties:
                id:
                  $ref: '#/components/schemas/CustomerId'
                status:
                  type: string
                  enum:
                    - under_review
                    - active
                external_id:
                  type:
                    - string
                    - 'null'
    WebhookEvent_CustomerKycUpdated:
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - customer.kyc_updated
            data:
              type: object
              required:
                - id
                - status
                - external_id
                - kyc
              properties:
                id:
                  $ref: '#/components/schemas/CustomerId'
                status:
                  type: string
                  enum:
                    - pending_kyc
                    - under_review
                    - active
                external_id:
                  type:
                    - string
                    - 'null'
                kyc:
                  type: array
                  description: Full current state of all KYC requirements
                  items:
                    $ref: '#/components/schemas/KycItem'
    WebhookEvent_CreditOffer:
      description: Used for `credit_offer.available` and `credit_offer.expired` events.
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - credit_offer.available
                - credit_offer.expired
            data:
              type: object
              required:
                - id
                - customer_id
                - status
                - approved_amount
                - min_amount
                - interest_rate
                - installments
                - valid_until
              properties:
                id:
                  $ref: '#/components/schemas/CreditOfferId'
                customer_id:
                  $ref: '#/components/schemas/CustomerId'
                status:
                  type: string
                  enum:
                    - available
                    - expired
                approved_amount:
                  $ref: '#/components/schemas/Money'
                min_amount:
                  type: string
                  pattern: ^\d+\.\d{2}$
                  description: Minimum withdrawal amount
                interest_rate:
                  type: number
                  description: Monthly interest rate percentage
                installments:
                  type: integer
                  description: Number of installments
                due_date_rule:
                  type:
                    - string
                    - 'null'
                  description: Due date rule for installments. Pending Core implementation.
                valid_until:
                  type: string
                  format: date-time
    WebhookEvent_LoanCreated:
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - loan.created
            data:
              type: object
              required:
                - id
                - credit_offer_id
                - customer_id
                - status
                - requested_amount
                - number_of_installments
              properties:
                id:
                  $ref: '#/components/schemas/LoanId'
                credit_offer_id:
                  $ref: '#/components/schemas/CreditOfferId'
                customer_id:
                  $ref: '#/components/schemas/CustomerId'
                status:
                  type: string
                  enum:
                    - processing
                requested_amount:
                  $ref: '#/components/schemas/Money'
                number_of_installments:
                  type: integer
      description: Event fired when a loan is created.
    WebhookEvent_LoanContract:
      description: >-
        Used for `loan.contract_generated` and `loan.awaiting_signatures`
        events.
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - loan.contract_generated
                - loan.awaiting_signatures
            data:
              type: object
              required:
                - id
                - status
                - signing_url
              properties:
                id:
                  $ref: '#/components/schemas/LoanId'
                status:
                  type: string
                  enum:
                    - contract_generated
                    - awaiting_signatures
                signing_url:
                  type: string
                  format: uri
                  description: ClickSign widget URL for customer signing
    WebhookEvent_LoanSigned:
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - loan.signed
            data:
              type: object
              required:
                - id
                - status
                - ccb_number
              properties:
                id:
                  $ref: '#/components/schemas/LoanId'
                status:
                  type: string
                  enum:
                    - signed
                ccb_number:
                  type: string
                  example: CCB-2026-001234
      description: Event fired when the loan contract is signed.
    WebhookEvent_LoanDisbursing:
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - loan.disbursing
            data:
              type: object
              required:
                - id
                - status
                - disbursement_method
              properties:
                id:
                  $ref: '#/components/schemas/LoanId'
                status:
                  type: string
                  enum:
                    - disbursing
                disbursement_method:
                  type: string
                  example: pix
      description: Event fired when loan disbursement begins.
    WebhookEvent_LoanActive:
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - loan.active
            data:
              type: object
              required:
                - id
                - status
                - requested_amount
                - net_amount
              properties:
                id:
                  $ref: '#/components/schemas/LoanId'
                status:
                  type: string
                  enum:
                    - active
                requested_amount:
                  $ref: '#/components/schemas/Money'
                net_amount:
                  $ref: '#/components/schemas/Money'
      description: Event fired when the loan becomes active.
    WebhookEvent_LoanPaymentReceived:
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - loan.payment_received
            data:
              type: object
              required:
                - id
                - status
                - payment
              properties:
                id:
                  $ref: '#/components/schemas/LoanId'
                status:
                  type: string
                  enum:
                    - active
                payment:
                  type: object
                  required:
                    - amount
                    - paid_at
                    - installment_number
                  properties:
                    amount:
                      $ref: '#/components/schemas/Money'
                    paid_at:
                      type: string
                      format: date-time
                    installment_number:
                      type: integer
      description: Event fired when an installment payment is received.
    WebhookEvent_LoanStatus:
      description: Used for `loan.finished`, `loan.cancelled`, and `loan.error` events.
      allOf:
        - $ref: '#/components/schemas/WebhookEventBase'
        - type: object
          properties:
            type:
              type: string
              enum:
                - loan.finished
                - loan.cancelled
                - loan.error
            data:
              type: object
              required:
                - id
                - status
              properties:
                id:
                  $ref: '#/components/schemas/LoanId'
                status:
                  type: string
                  enum:
                    - finished
                    - cancelled
                    - error
