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

> ## Agent Instructions
> Documentação das APIs da DeliveryVip, em português. Regras que mais quebram integrações: (1) Merchant API: faça polling em GET /merchant/v3/events:polling no máximo a cada 30 s por token; confirme todo evento recebido com POST /merchant/v3/events/acknowledgment e corpo [{"id": "<eventId>"}] (o campo lido é id, não eventId), inclusive eventos repetidos ou que o sistema não trata; deduplique por eventId; o evento é só um aviso, busque o pedido na orderURL. (2) Tokens client_credentials valem 24 h e não têm refresh_token: peça outro ao receber 401. (3) Webhooks: valide a assinatura HMAC sobre o corpo bruto e responda 2xx rápido; o polling é a reconciliação. (4) Open Delivery: host od.deliveryvip.com.br, um client_secret por loja, datas em UTC. (5) Fidelidade: o operador implementa 5 rotas assinadas com HMAC e chama o config push; o estorno precisa ser idempotente. (6) Partner API: scope dv.partner. Não invente endpoints: use a referência gerada das specs OpenAPI.

# Locate-or-enroll the customer (opt-in)

> Sent when the customer opts into the program at checkout. The click IS the consent (consent.grantedAt is the moment of the click; timestamps carry the platform's UTC offset). The customer profile is attested by DeliveryVip (non-guest, complete profile). The operator may answer with a PIN challenge instead of an account: DeliveryVip then re-sends the same body plus challenge.answer typed by the customer. The PIN is validated exclusively on the operator side (rate limiting included) and is never stored by DeliveryVip. Answering with both id and challenge in one response is forbidden (DeliveryVip treats challenge as authoritative and discards the id).



## OpenAPI

````yaml https://app.deliveryvip.com.br/swaggers/loyalty_operator.yaml post /v1/loyalty/accounts:link
openapi: 3.0.3
info:
  version: v1
  title: DeliveryVip Loyalty Operator Contract
  description: >-
    The HTTP contract a loyalty operator must implement to serve the DeliveryVip
    loyalty extension. DeliveryVip is the ordering application: it CALLS these
    endpoints on the api_base_url declared by the operator's app (loyalty
    extension, dv.loyalty scope). Every request is signed with HMAC-SHA256 of
    the RAW body (empty string for body-less requests) using the app's OAuth
    secret — verify the signature against the exact bytes received, never a
    re-serialization. Respond fast: DeliveryVip uses 3s connect / 5s read
    timeouts, and 5 transport failures (timeout/5xx) within 5 minutes open a
    circuit breaker for the whole extension. Business answers (409/422/403/404)
    never count as failures. Configuration is pushed the other way (operator ->
    DeliveryVip) via PUT/DELETE /merchant/v3/{merchantId}/loyalty/config — see
    the Merchant API swagger; the PUT triggers a synchronous signed GET
    /v1/loyalty/ping here before anything is stored. That push is also where an
    operator declares its commercial boundaries per order
    (capabilities.redemptionLimits: an optional min and max, each fixed BRL or
    percent of the redeemable base). DeliveryVip enforces them before calling
    this API, so the amount below always already respects whatever the operator
    declared. Canonical byte-pinned request/response examples live in the
    platform repository under test/fixtures/files/loyalty/.
servers:
  - url: '{api_base_url}'
    description: >-
      The base URL the operator declares on the loyalty extension (https only;
      may include a path prefix).
    variables:
      api_base_url:
        default: https://operator.example.com/dv/v1
security:
  - appId: []
    appMerchantId: []
    appSignature: []
tags:
  - name: Handshake
    description: Synchronous verification during the config push.
  - name: Accounts
    description: >-
      Customer identity and balance. The account id must be opaque and stable
      across relinks.
  - name: Redemptions
    description: Synchronous balance debit (checkout) and its explicit idempotent reversal.
paths:
  /v1/loyalty/accounts:link:
    post:
      tags:
        - Accounts
      summary: Locate-or-enroll the customer (opt-in)
      description: >-
        Sent when the customer opts into the program at checkout. The click IS
        the consent (consent.grantedAt is the moment of the click; timestamps
        carry the platform's UTC offset). The customer profile is attested by
        DeliveryVip (non-guest, complete profile). The operator may answer with
        a PIN challenge instead of an account: DeliveryVip then re-sends the
        same body plus challenge.answer typed by the customer. The PIN is
        validated exclusively on the operator side (rate limiting included) and
        is never stored by DeliveryVip. Answering with both id and challenge in
        one response is forbidden (DeliveryVip treats challenge as authoritative
        and discards the id).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/linkRequest'
      responses:
        '200':
          description: Account located/enrolled, or a challenge is required first.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/linkedAccount'
                  - $ref: '#/components/schemas/challenge'
        '403':
          description: >-
            Challenge rejected (wrong PIN). The body must be generic: it must
            not reveal whether the account exists.
        '404':
          description: Enrollment closed — the customer must sign up at the store first.
components:
  schemas:
    linkRequest:
      type: object
      required:
        - programId
        - customer
        - consent
        - enroll
      properties:
        programId:
          type: string
          description: >-
            The operator-side program identifier (as pushed in the merchant
            configuration).
        customer:
          type: object
          required:
            - document
            - phone
            - email
            - name
            - birthDate
          properties:
            document:
              type: string
              description: CPF, digits only.
            phone:
              type: string
              description: E.164 (e.g. +5511999998888).
            email:
              type: string
              format: email
            name:
              type: string
            birthDate:
              type: string
              format: date
        consent:
          type: object
          required:
            - purpose
            - status
            - grantedAt
          properties:
            purpose:
              type: string
              enum:
                - loyalty_program
            status:
              type: string
              enum:
                - granted
            grantedAt:
              type: string
              format: date-time
        enroll:
          type: boolean
          description: >-
            Whether the program accepts enrollment through checkout (mirrors the
            pushed capability).
        challenge:
          type: object
          description: Present only on the re-send after a PIN challenge.
          required:
            - type
            - answer
          properties:
            type:
              type: string
              enum:
                - pin
            answer:
              type: string
    linkedAccount:
      type: object
      description: >-
        The account located or enrolled by accounts:link. The balance is not
        part of this answer — DeliveryVip reads it from the balance endpoint.
      required:
        - id
        - programId
        - balanceType
      properties:
        id:
          type: string
          description: >-
            Opaque and STABLE — relinking the same customer must return the same
            id byte-for-byte.
        programId:
          type: string
        balanceType:
          type: string
          enum:
            - cashback
    challenge:
      type: object
      required:
        - challenge
      properties:
        challenge:
          type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - pin
  securitySchemes:
    appId:
      type: apiKey
      in: header
      name: X-App-Id
      description: The uid of the operator's OAuth application on DeliveryVip.
    appMerchantId:
      type: apiKey
      in: header
      name: X-App-MerchantId
      description: The UUID of the merchant (company) the call concerns.
    appSignature:
      type: apiKey
      in: header
      name: X-App-Signature
      description: >-
        Hex HMAC-SHA256 of the raw request body (empty string when there is no
        body), keyed with the app's OAuth secret. Verify against the exact bytes
        received.

````

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