Skip to content
Amir Iranmanesh edited this page Jul 31, 2026 · 2 revisions

FAQ

Why zero dependencies?

Payment code lives long and is audited often. A package that pulls a SOAP library, an HTTP client and a logger drags their CVEs, their release cadence and their opinions into your service. Everything Payvand needs — SOAP envelopes, 3DES, AES, RSA, retries — fits comfortably in the standard library, so it stays there. CI fails the build if a require block ever appears in go.mod.

Which Go version?

1.26 or newer.

Is a gateway safe for concurrent use?

Yes. Build one per terminal at start-up and share it across requests.

Rial or Toman?

Whichever you have. payvand.Rial(150_000) and payvand.Toman(15_000) are the same money, and each gateway converts to what its own API expects — Rial for most, Toman for PayPing, either for Zarinpal depending on the terminal.

Do I really have to call Verify?

Yes. Most Iranian gateways reverse a transaction that is never verified, within 15 to 30 minutes. Callback.Succeeded only says the payer got to the end of the bank page.

The payer closed the tab. Now what?

Ask the provider with Inquiry, then verify if it reports the money as taken. See Callbacks and Verification. Gateways without an inquiry API have to be reconciled from the provider panel.

Why does Refund return ErrNotSupported?

Because that provider offers no refund API to merchants — Zarinpal, Zibal, IDPay, Pay.ir, PayPing, BitPay, YekPay, PayWeb, Sadad and Iran Kish are in that group today. Check gw.Capabilities().Refund before offering the button.

Can I add a gateway without forking?

Yes. Implement core.Gateway in your own module and call payvand.Register. See Extending.

Why is OrderID sometimes rejected?

Sadad, TOP, Mellat and Sepehr require a numeric, unique order id. Use your order's integer primary key, or a numeric sequence dedicated to payments.

What is the virtual gateway for?

Development, tests and staging. It runs the whole cycle in memory, with options to decline payments or fail verification, so you can exercise the unhappy paths without a terminal.

Does Payvand store anything?

No. It has no database, no cache and no background goroutine. Tokens, orders and reconciliation are yours.

How do I log the provider exchange?

payvand.WithLogger(payvand.SlogLogger{Logger: slog.Default()}), or any type with Debug and Error. Every request and response passes through it — redact before shipping to an aggregator, because the bodies contain terminal credentials.

Does it support instalments, bills or wallets?

Only through the providers' generic transaction types today: irankish.WithTransactionType, asanpardakht.WithServiceType, pasargad.WithAction and asanpardakht.WithPaymentID. First class support is on the Roadmap.

Why is WithSkipTLSVerify there at all?

Some Shaparak hosts have historically served incomplete certificate chains. It is off by default, documented as a last resort, and should be scoped to the one gateway that needs it.

Is the API stable?

Yes, for the whole 1.x line: payvand and payvand/core follow semantic versioning. Packages under internal/ are not part of the contract.

The provider changed its API. What now?

Open an issue with the raw request and response (credentials redacted) and the date. Iranian PSPs change without notice, and that report is usually enough for a one-commit fix.

Can I use it with a proxy or mTLS?

Yes: payvand.WithHTTPClient takes any Do(*http.Request) (*http.Response, error), so bring your own transport.

Clone this wiki locally