Complete UPI Setu (UMAP) API client.
Covers Flash (DQR / SQR), Collect, TPV, Mandates (recurring / one-time / SBMD), mandate operations, pre-debit notifications, execution, refunds, disputes, and aggregator merchant onboarding.
All endpoints authenticate with Bearer tokens managed by SetuClient.TokenManager.
Example
cfg = SetuClient.Config.new(client_id: "...", client_secret: "...")
{:ok, qr} = SetuClient.Payments.UPI.create_dqr(cfg, merchant_id, %{
merchant_vpa: "shop@pineaxis",
amount: 10_000
})
Summary
Functions
Accepts a customer dispute, triggering an automatic refund.
Checks whether a VPA is available for assignment. Call before create_vpa/3.
Creates a UPI Collect request — pushes a notification to the customer's UPI app.
Creates a Dynamic QR (DQR) — a single-use UPI payment link / QR code.
Creates a UPI Mandate — supports recurring, one-time, and SBMD.
Onboards a new merchant under an aggregator account.
Initiates a refund for a completed UPI payment (within 60 days).
Creates a Static QR (SQR) — permanent multi-use QR for in-store display.
Creates a TPV payment link.
Assigns a VPA to a merchant (aggregator only).
Executes a mandate — debits the customer's bank account.
Fetches the status of a collect request.
Retrieves the details of a customer dispute.
Fetches a Dynamic QR by its ID.
Returns the most recent payment on any product instance (DQR, SQR, TPV, Collect).
Retrieves the current status of a mandate.
Retrieves the status of a mandate execution.
Retrieves the status of a mandate operation (update / revoke / pause / unpause).
Retrieves a merchant by ID (aggregator only).
Returns the 5 most recent payments on a product instance.
Retrieves the status of a pre-debit notification.
Retrieves the status of a refund.
Fetches a Static QR by its ID.
Fetches a TPV link by its ID.
Sends a pre-debit notification 48–72 hours before mandate execution.
Contests a dispute by submitting evidence to NPCI.
Initiates merchant-side mandate revocation.
Updates a mandate's amount limit or end date.
Verifies whether a customer VPA is valid before creating a collect request.
Functions
@spec accept_dispute(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Accepts a customer dispute, triggering an automatic refund.
PUT /v1/merchants/disputes/{id}/accept
@spec check_vpa_availability(SetuClient.Config.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Checks whether a VPA is available for assignment. Call before create_vpa/3.
POST /v1/aggregators/vpa/check
@spec create_collect(SetuClient.Config.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Creates a UPI Collect request — pushes a notification to the customer's UPI app.
Deprecated by NPCI. Prefer DQR for new integrations.
Required params
:customer_vpa,:merchant_vpa,:merchant_reference_id,:amount(paise)
POST /v1/merchants/collect
@spec create_dqr(SetuClient.Config.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Creates a Dynamic QR (DQR) — a single-use UPI payment link / QR code.
Amount behaviour
- Only
:amount→ fixed amount displayed, customer cannot change it - Only
:min_amount→ customer chooses ≥ min_amount - Both → amount displayed, customer can change it
Required params
:merchant_vpa
POST /v1/merchants/dqr
@spec create_mandate(SetuClient.Config.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Creates a UPI Mandate — supports recurring, one-time, and SBMD.
Mandate types
| Type | Key params |
|---|---|
| Recurring | frequency: "monthly", purpose: "14", block_funds: false |
| One-time | frequency: "one time", recurrence_value: 0 |
| SBMD | frequency: "as presented", purpose: "76", block_funds: true |
Required params
:merchant_vpa, :start_date (ddMMyyyy), :end_date (ddMMyyyy), :frequency
POST /v1/merchants/mandates
@spec create_merchant(SetuClient.Config.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Onboards a new merchant under an aggregator account.
Required params
:aggregator_account_id,:business_name
POST /v1/aggregators/merchants
@spec create_refund(SetuClient.Config.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Initiates a refund for a completed UPI payment (within 60 days).
Required params
:payment_id,:amount(paise),:merchant_reference_id
POST /v1/merchants/refunds
@spec create_sqr(SetuClient.Config.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Creates a Static QR (SQR) — permanent multi-use QR for in-store display.
Required params
:merchant_vpa
POST /v1/merchants/sqr
@spec create_tpv(SetuClient.Config.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Creates a TPV payment link.
Payment is accepted only if the customer pays from the registered bank account. Mandatory for SEBI-regulated merchants (mutual funds, equities, bonds).
Required params
:merchant_vpa:customer_account— map with:ifscand:account_number
POST /v1/merchants/tpv
@spec create_vpa(SetuClient.Config.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Assigns a VPA to a merchant (aggregator only).
Required params
:vpa
POST /v1/merchants/vpas
@spec execute_mandate(SetuClient.Config.t(), String.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Executes a mandate — debits the customer's bank account.
Required params
:amount(paise),:umn,:sequence_number,:merchant_reference_id
POST /v1/merchants/mandates/{id}/execute
@spec get_collect(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Fetches the status of a collect request.
GET /v1/merchants/collect/{id}
@spec get_dispute(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Retrieves the details of a customer dispute.
GET /v1/merchants/disputes/{id}
@spec get_dqr(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Fetches a Dynamic QR by its ID.
GET /v1/merchants/dqr/{id}
@spec get_last_payment(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Returns the most recent payment on any product instance (DQR, SQR, TPV, Collect).
GET /v1/merchants/payments/product-instances/{id}/last
@spec get_mandate(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Retrieves the current status of a mandate.
GET /v1/merchants/mandates/{id}
@spec get_mandate_execution(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Retrieves the status of a mandate execution.
GET /v1/merchants/mandate-executions/{id}
@spec get_mandate_operation(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Retrieves the status of a mandate operation (update / revoke / pause / unpause).
GET /v1/merchants/mandate-operations/{id}
@spec get_merchant(SetuClient.Config.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Retrieves a merchant by ID (aggregator only).
GET /v1/aggregators/merchants/{id}
@spec get_payment_history(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Returns the 5 most recent payments on a product instance.
GET /v1/merchants/payments/product-instances/{id}/history
@spec get_pre_debit_notification(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Retrieves the status of a pre-debit notification.
GET /v1/merchants/mandate-pre-debit-notifications/{id}
@spec get_refund(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Retrieves the status of a refund.
GET /v1/merchants/refunds/{id}
@spec get_sqr(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Fetches a Static QR by its ID.
GET /v1/merchants/sqr/{id}
@spec get_tpv(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Fetches a TPV link by its ID.
GET /v1/merchants/tpv/{id}
@spec pre_debit_notify(SetuClient.Config.t(), String.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Sends a pre-debit notification 48–72 hours before mandate execution.
Required params
:amount(paise),:execution_date(ddMMyyyy),:umn,:sequence_number,:merchant_reference_id
POST /v1/merchants/mandates/{id}/notify
@spec reject_dispute(SetuClient.Config.t(), String.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Contests a dispute by submitting evidence to NPCI.
Required params
:evidence— base64-encoded document
PUT /v1/merchants/disputes/{id}/reject
@spec revoke_mandate(SetuClient.Config.t(), String.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Initiates merchant-side mandate revocation.
PUT /v1/merchants/mandates/{id}/revoke
@spec update_mandate(SetuClient.Config.t(), String.t(), String.t(), map()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Updates a mandate's amount limit or end date.
Required params
:merchant_reference_id
PUT /v1/merchants/mandates/{id}/modify
@spec verify_vpa(SetuClient.Config.t(), String.t(), String.t()) :: {:ok, map()} | {:error, SetuClient.Error.t()}
Verifies whether a customer VPA is valid before creating a collect request.
GET /v1/merchants/vpa/validate?vpa={vpa}