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

# Criar link de pagamento

> Cria um link de pagamento a partir de um produto cadastrado (`productId`). Requer `Idempotency-Key` obrigatório — o identificador do link deriva dela de forma determinística, então reenviar a mesma chave com o mesmo corpo retorna o mesmo link. Devolve `201 Created` na primeira criação e `200 OK` em reentrega idempotente. A resposta **não** inclui uma URL pronta para compartilhar: use o produto hospedado do app quando precisar de uma URL.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/payment-links
openapi: 3.1.0
info:
  title: TroqPay API
  description: >-
    API da TroqPay para criar cobranças Pix, ler saldo, solicitar saques em
    produção e processar eventos por webhook.
  version: 1.0.0
servers:
  - url: https://api.troqpay.com
    description: >-
      Use a mesma URL-base para teste e produção. O ambiente é definido pela
      chave utilizada (`trq_test_` ou `trq_live_`).
security:
  - bearerAuth: []
tags:
  - name: Checkouts
    description: Criação e consulta de cobranças Pix.
  - name: Payment Links
    description: >-
      Criação, listagem e consulta de links de pagamento a partir de produtos
      cadastrados.
  - name: Saldo
    description: >-
      Leitura do saldo agregado da conta TroqPay (valores em decimal, todos em
      BRL).
  - name: Saques
    description: Criação e consulta de saques em produção.
  - name: Webhooks
    description: Eventos enviados pela TroqPay quando um checkout muda de estado.
  - name: Status
    description: Endpoints públicos para verificar disponibilidade da API.
paths:
  /v1/payment-links:
    post:
      tags:
        - Payment Links
      summary: Criar link de pagamento
      description: >-
        Cria um link de pagamento a partir de um produto cadastrado
        (`productId`). Requer `Idempotency-Key` obrigatório — o identificador do
        link deriva dela de forma determinística, então reenviar a mesma chave
        com o mesmo corpo retorna o mesmo link. Devolve `201 Created` na
        primeira criação e `200 OK` em reentrega idempotente. A resposta **não**
        inclui uma URL pronta para compartilhar: use o produto hospedado do app
        quando precisar de uma URL.
      operationId: createPaymentLink
      parameters:
        - $ref: '#/components/parameters/RequiredIdempotencyKeyHeader'
        - $ref: '#/components/parameters/RequestIdHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentLinkCreateRequest'
            examples:
              basic:
                summary: Link a partir de um produto
                value:
                  productId: plano-pro
                  expiresInSeconds: 1800
                  successUrl: https://loja.example.com/obrigado
                  returnUrl: https://loja.example.com/carrinho
      responses:
        '200':
          description: >-
            Resposta idempotente: a mesma `Idempotency-Key` foi usada com o
            mesmo corpo. A API devolve o link já existente em vez de criar um
            novo.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestIdResponseHeader'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLink'
        '201':
          description: Link de pagamento criado com sucesso.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestIdResponseHeader'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentLink'
              examples:
                created:
                  summary: Link criado
                  value:
                    paymentLinkId: pl_4a8b3c1d5e6f2a9b0c1d
                    livemode: false
                    active: true
                    productId: plano-pro
                    amount: 12990
                    currency: BRL
                    name: Plano Pro
                    description: Assinatura mensal do Plano Pro
                    imageUrl: null
                    paymentCycle: MONTHLY
                    expiresInSeconds: 1800
                    successUrl: https://loja.example.com/obrigado
                    returnUrl: https://loja.example.com/carrinho
                    createdAt: '2026-04-25T14:00:00.000Z'
                    updatedAt: '2026-04-25T14:00:00.000Z'
        '400':
          description: Corpo inválido, JSON malformado ou `Idempotency-Key` ausente.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestIdResponseHeader'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingIdempotency:
                  summary: Idempotency-Key obrigatório
                  value:
                    error:
                      type: validation_error
                      code: idempotency_key_required
                      message: >-
                        Idempotency-Key header is required for payment-link
                        creation.
                      requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
                invalidRequestBody:
                  summary: Falha de validação no corpo
                  value:
                    error:
                      type: validation_error
                      code: invalid_request_body
                      message: successUrl must be a valid http(s) URL
                      requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            Conta sem acesso a produção ou chave sem permissão para criar links
            de pagamento.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestIdResponseHeader'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                forbidden:
                  summary: Chave LIVE em conta não aprovada
                  value:
                    error:
                      type: auth_error
                      code: forbidden
                      message: API key does not have access to live-mode payment links
                      requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
                missingPermission:
                  summary: Chave sem permissão de criação de link
                  value:
                    error:
                      type: auth_error
                      code: api_key_scope_forbidden
                      message: >-
                        API key does not have permission to access this
                        resource.
                      requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
        '404':
          description: >-
            Nenhum produto ativo encontrado para o `productId` no projeto e
            ambiente da chave.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestIdResponseHeader'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                productNotFound:
                  summary: Produto inexistente ou inativo
                  value:
                    error:
                      type: not_found_error
                      code: product_not_found
                      message: >-
                        Active product not found for the current project and
                        environment.
                      requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
        '422':
          description: Regra de negócio não atendida.
          headers:
            Request-Id:
              $ref: '#/components/headers/RequestIdResponseHeader'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                invalidExpiresIn:
                  summary: expiresInSeconds fora do intervalo
                  value:
                    error:
                      type: business_error
                      code: invalid_expires_in
                      message: expiresIn must be between 900 and 86400 seconds
                      requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
        '429':
          $ref: '#/components/responses/RateLimited'
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: |-
            curl -X POST https://api.troqpay.com/v1/payment-links \
              -H "Authorization: Bearer trq_test_xxx" \
              -H "Content-Type: application/json" \
              -H "Idempotency-Key: link_1001" \
              -d '{
                "productId": "plano-pro",
                "expiresInSeconds": 1800,
                "successUrl": "https://loja.example.com/obrigado",
                "returnUrl": "https://loja.example.com/carrinho"
              }'
        - lang: JavaScript
          label: JavaScript
          source: >-
            const response = await
            fetch("https://api.troqpay.com/v1/payment-links", {
              method: "POST",
              headers: {
                "Authorization": "Bearer trq_test_xxx",
                "Content-Type": "application/json",
                "Idempotency-Key": "link_1001"
              },
              body: JSON.stringify({
                productId: "plano-pro",
                expiresInSeconds: 1800,
                successUrl: "https://loja.example.com/obrigado",
                returnUrl: "https://loja.example.com/carrinho"
              })
            });


            const paymentLink = await response.json();
components:
  parameters:
    RequiredIdempotencyKeyHeader:
      name: Idempotency-Key
      in: header
      required: true
      description: >-
        Chave de idempotência obrigatória para criação de saque. Mesma chave e
        mesmo corpo retornam o mesmo saque; mesma chave com corpo diferente
        retorna `409 idempotency_conflict`.
      schema:
        type: string
        example: withdrawal_1001
    RequestIdHeader:
      name: Request-Id
      in: header
      required: false
      description: >-
        Identificador opcional fornecido pelo cliente para correlação. A API
        aceita também `X-Request-Id`. O valor é ecoado de volta no header de
        resposta `Request-Id`. Se nenhum dos dois é enviado, a API gera `req_<24
        hex>`.
      schema:
        type: string
        example: req_4a8b3c1d5e6f2a9b0c1d2e3f
  schemas:
    PaymentLinkCreateRequest:
      type: object
      required:
        - productId
      description: >-
        Payload para criar um link de pagamento a partir de um produto
        cadastrado.
      properties:
        productId:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            Identificador do produto (slug) cadastrado no projeto. O produto
            precisa estar ativo no mesmo ambiente da chave.
          example: plano-pro
        expiresInSeconds:
          type: integer
          minimum: 900
          maximum: 86400
          default: 1800
          example: 1800
          description: >-
            Tempo de expiração, em segundos, das cobranças geradas pelo link.
            Entre 900 e 86400. O padrão é 1800 (30 minutos).
        successUrl:
          type:
            - string
            - 'null'
          format: uri
          maxLength: 2048
          description: >-
            URL http(s) opcional para redirecionar o comprador após o pagamento.
            Uma string vazia equivale a não enviar.
          example: https://loja.example.com/obrigado
        returnUrl:
          type:
            - string
            - 'null'
          format: uri
          maxLength: 2048
          description: >-
            URL http(s) opcional para o comprador voltar sem concluir o
            pagamento. Uma string vazia equivale a não enviar.
          example: https://loja.example.com/carrinho
    PaymentLink:
      type: object
      required:
        - paymentLinkId
        - livemode
        - active
        - productId
        - amount
        - currency
        - name
        - description
        - imageUrl
        - paymentCycle
        - expiresInSeconds
        - successUrl
        - returnUrl
        - createdAt
        - updatedAt
      description: >-
        Link de pagamento. A resposta **não** inclui uma URL pronta para
        compartilhar — apenas o `paymentLinkId` e os dados do link/produto. Para
        uma URL hospedada, use o produto hospedado do app.
      properties:
        paymentLinkId:
          type: string
          description: Identificador do link de pagamento.
          example: pl_4a8b3c1d5e6f2a9b0c1d
        livemode:
          type: boolean
          description: '`true` para chaves `trq_live_`; `false` para `trq_test_`.'
          example: false
        active:
          type: boolean
          description: Indica se o link está ativo.
          example: true
        productId:
          type: string
          description: Identificador (slug) do produto associado ao link.
          example: plano-pro
        amount:
          type: integer
          description: Valor do produto em centavos de BRL.
          example: 12990
        currency:
          type: string
          description: Moeda do link. Hoje, sempre `BRL`.
          enum:
            - BRL
          example: BRL
        name:
          type: string
          description: Nome do produto associado ao link.
          example: Plano Pro
        description:
          type:
            - string
            - 'null'
          description: Descrição do produto, quando informada.
          example: Assinatura mensal do Plano Pro
        imageUrl:
          type:
            - string
            - 'null'
          description: URL da imagem do produto, quando informada.
          example: null
        paymentCycle:
          type: string
          description: Ciclo de cobrança do produto associado ao link.
          example: MONTHLY
        expiresInSeconds:
          type: integer
          description: Tempo de expiração, em segundos, das cobranças geradas pelo link.
          example: 1800
        successUrl:
          type:
            - string
            - 'null'
          description: URL de redirecionamento após o pagamento, quando definida.
          example: https://loja.example.com/obrigado
        returnUrl:
          type:
            - string
            - 'null'
          description: URL de retorno sem concluir o pagamento, quando definida.
          example: https://loja.example.com/carrinho
        createdAt:
          type: string
          format: date-time
          description: Quando o link foi criado.
        updatedAt:
          type: string
          format: date-time
          description: Quando o link foi atualizado pela última vez.
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/ErrorBody'
    ErrorBody:
      type: object
      required:
        - type
        - code
        - message
        - requestId
      description: >-
        Corpo padronizado de erro da API. As mensagens em `message` chegam em
        inglês — é o que a API emite literalmente.
      properties:
        type:
          type: string
          description: Categoria do erro.
          enum:
            - auth_error
            - validation_error
            - business_error
            - not_found_error
            - conflict_error
            - provider_error
            - rate_limit_error
            - internal_error
          example: validation_error
        code:
          type: string
          description: Código estável para tratar a falha no seu backend.
          example: invalid_request_body
        message:
          type: string
          description: Mensagem legível do erro (em inglês, literal).
          example: Number must be greater than 0
        requestId:
          type: string
          description: Identificador da requisição para logs e investigação.
          example: req_4a8b3c1d5e6f2a9b0c1d2e3f
  headers:
    RequestIdResponseHeader:
      description: >-
        Identificador da requisição. Sempre presente. Ecoa o valor enviado em
        `Request-Id` ou `X-Request-Id`, ou um identificador gerado pela API no
        formato `req_<24 hex>`.
      schema:
        type: string
        example: req_4a8b3c1d5e6f2a9b0c1d2e3f
  responses:
    Unauthorized:
      description: >-
        Chave ausente, mal formatada, inválida ou revogada. A API sempre devolve
        `code: "unauthorized"` em 401.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestIdResponseHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            unauthorized:
              summary: Bearer ausente ou inválido
              value:
                error:
                  type: auth_error
                  code: unauthorized
                  message: invalid or missing bearer token
                  requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
    RateLimited:
      description: Limite de requisições excedido. Faça retry com backoff.
      headers:
        Request-Id:
          $ref: '#/components/headers/RequestIdResponseHeader'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            rateLimited:
              summary: Limite excedido
              value:
                error:
                  type: rate_limit_error
                  code: rate_limit_exceeded
                  message: Too many requests. Please retry with backoff.
                  requestId: req_4a8b3c1d5e6f2a9b0c1d2e3f
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key

````