SetuClient.Payments.UPI (Setu Client v1.0.0)

Copy Markdown View Source

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

accept_dispute(cfg, merchant_id, dispute_id)

@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

check_vpa_availability(cfg, vpa)

@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

create_collect(cfg, merchant_id, params)

@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

create_dqr(cfg, merchant_id, params)

@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

create_mandate(cfg, merchant_id, params)

@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

TypeKey params
Recurringfrequency: "monthly", purpose: "14", block_funds: false
One-timefrequency: "one time", recurrence_value: 0
SBMDfrequency: "as presented", purpose: "76", block_funds: true

Required params

:merchant_vpa, :start_date (ddMMyyyy), :end_date (ddMMyyyy), :frequency

POST /v1/merchants/mandates

create_merchant(cfg, params)

@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

create_refund(cfg, merchant_id, params)

@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

create_sqr(cfg, merchant_id, params)

@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

create_tpv(cfg, merchant_id, params)

@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 :ifsc and :account_number

POST /v1/merchants/tpv

create_vpa(cfg, merchant_id, params)

@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

execute_mandate(cfg, merchant_id, mandate_id, params)

@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

get_collect(cfg, merchant_id, collect_id)

@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}

get_dispute(cfg, merchant_id, dispute_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}

get_dqr(cfg, merchant_id, dqr_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}

get_last_payment(cfg, merchant_id, product_instance_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

get_mandate(cfg, merchant_id, mandate_id)

@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}

get_mandate_execution(cfg, merchant_id, execution_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}

get_mandate_operation(cfg, merchant_id, operation_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}

get_merchant(cfg, merchant_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}

get_payment_history(cfg, merchant_id, product_instance_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

get_pre_debit_notification(cfg, merchant_id, notification_id)

@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}

get_refund(cfg, merchant_id, refund_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}

get_sqr(cfg, merchant_id, sqr_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}

get_tpv(cfg, merchant_id, tpv_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}

pre_debit_notify(cfg, merchant_id, mandate_id, params)

@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

reject_dispute(cfg, merchant_id, dispute_id, params)

@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

revoke_mandate(cfg, merchant_id, mandate_id, params \\ %{})

@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

update_mandate(cfg, merchant_id, mandate_id, params)

@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

verify_vpa(cfg, merchant_id, vpa)

@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}