Libraries
Official libraries wrap the API for Node.js, Python, PHP, Go and Dart. They all do the same things: create and read payments, list the coins a customer can pay with, manage your webhook (IPN) URL, verify webhook notifications in one call, and call the public checkout API. Field names are the API's own, so everything in these docs applies. Each library has a full reference page.
| Language | Reference | Install | Import | Needs |
|---|---|---|---|---|
| Node.js / TypeScript | Node.js library | npm install @payitgo/node |
import { Payitgo } from "@payitgo/node" |
Node 18+, no dependencies |
| Python | Python library | pip install payitgo |
import payitgo |
Python 3.8+, no dependencies |
| PHP | PHP library | composer require payitgo/payitgo-php |
use Payitgo\Client; |
PHP 8.1+, curl and json |
| Go | Go library | go get github.com/payitgo/go-sdk |
import payitgo "github.com/payitgo/go-sdk" |
Go 1.21+, no dependencies |
| Dart / Flutter | Dart and Flutter library | dart pub add payitgo |
import 'package:payitgo/payitgo.dart'; |
Dart 3, http and crypto |
The Python package is published as payitgo and imported as payitgo.
A WooCommerce shop needs no code: the WooCommerce plugin adds crypto to its checkout and marks orders paid by itself.
Use the libraries on your server: they need your secret key. The
exceptions need no key, only the payment's checkout_token from your server:
Dart's PayitgoCheckout, made for Flutter apps, and the
React checkout widget, which shows the payment in a modal
in a React app.
Creating a client
Every client takes your secret key and the same options. The key decides the
mode: a test key works with test payments and the test webhook and its
secret, a live key with live ones. Use the webhook secret of the same
mode. A missing key is refused when the client is created, before any
request. The key's text does not say its mode: ask payitgo with isLive()
(the first call reads it, later ones use the answer).
| Option | Node | Python | PHP | Go | Dart |
|---|---|---|---|---|---|
| Constructor | new Payitgo(key, {…}) |
payitgo.Client(key, …) |
new \Payitgo\Client($key, [...]) |
payitgo.NewClient(key, …) |
Payitgo(key, …) |
Base URL, https://api.payitgo.co |
baseUrl |
base_url |
'base_url' |
payitgo.WithBaseURL(u) |
baseUrl |
| Base URL from the environment | PAYITGO_BASE_URL |
PAYITGO_BASE_URL |
PAYITGO_BASE_URL |
PAYITGO_BASE_URL |
No: pass it yourself |
| Timeout per attempt (default 30 s) | timeoutMs |
timeout (seconds) |
'timeout' (seconds) |
The HTTP client's Timeout, and your ctx |
timeout (Duration) |
| Retries (default 2) | maxRetries |
max_retries |
'max_retries' |
payitgo.WithMaxRetries(n) |
maxRetries |
| Your own HTTP client | No | No | No | payitgo.WithHTTPClient(h) |
httpClient |
| Webhook secret | webhookSecret |
webhook_secret |
'webhook_secret' |
payitgo.WithWebhookSecret(s) |
webhookSecret |
Default webhook_url for payments |
webhookUrl |
webhook_url |
'webhook_url' |
payitgo.WithWebhookURL(u) |
webhookUrl |
| Test or live, asked of payitgo | await payitgo.isLive() |
client.is_live() |
$payitgo->isLive() |
client.IsLive(ctx) |
await payitgo.isLive() |
| A bad key or no address | Throws Error |
Raises ValueError |
Throws InvalidArgumentException |
Returns an error | Throws ArgumentError |
Without a base URL option, the libraries use PAYITGO_BASE_URL (except Dart),
then the gateway address they were released with.
Errors and retries
| Node | Python | PHP | Go | Dart | |
|---|---|---|---|---|---|
| A failed API call | PayitgoError |
payitgo.PayitgoError |
Payitgo\Exception\PayitgoException |
*payitgo.Error |
PayitgoException |
| Its HTTP status | .status |
.status |
->status |
.Status |
.status |
| Its message | .message |
.message |
->getMessage() |
.Message |
.message |
| A notification that fails verification | SignatureVerificationError |
payitgo.SignatureVerificationError |
Payitgo\Exception\SignatureVerificationException |
payitgo.ErrSignature (errors.Is) |
SignatureVerificationException |
- The status is the API's HTTP status, or
0when no answer came (a network error or a timeout). The message is the API'serrormessage (Errors and limits). - Retries. Network errors and timeouts,
429and5xxare retried up to twice (the retries option), after 0.5 s and then 1 s. Other statuses are never retried. Every call is safe to repeat: creating a payment again for the sameorder_idreturns its open payment, choosing a coin that was already chosen answers409, and setting or removing the webhook URL twice changes nothing.
Webhooks
Every library manages the webhook of the key's mode (get, set, remove,
test) and verifies notifications in constant time: it checks the
X-Webhook-Signature against the raw body, refuses a timestamp more than
5 minutes from your clock, and returns the parsed event
(how it works).
| Node | Python | PHP | Go | Dart | |
|---|---|---|---|---|---|
| With the client's webhook secret | payitgo.webhooks.constructEvent(body, sig) |
client.webhooks.construct_event(body, sig) |
$payitgo->webhooks->constructEvent($body, $sig) |
client.Webhooks.ConstructEvent(body, sig) |
payitgo.webhooks.constructEvent(body, sig) |
| With another secret | …(body, sig, secret) |
…(body, sig, secret) |
…($body, $sig, $secret) |
…(body, sig, secret) |
…(body, sig, secret: s) |
| Without a client | Payitgo.webhooks.constructEvent(body, sig, secret) |
payitgo.Webhook.construct_event(body, sig, secret) |
\Payitgo\Webhook::constructEvent($body, $sig, $secret) |
payitgo.ConstructEvent(body, sig, secret) |
Webhook.constructEvent(body, sig, secret) |
| Another tolerance | 4th argument, seconds | tolerance=, seconds |
4th argument, seconds | payitgo.ConstructEventWithTolerance(…, d) |
tolerance:, a Duration |
| The raw body | express.raw(…), then req.body |
request.get_data() (Flask) |
file_get_contents('php://input') |
io.ReadAll(r.Body) |
await request.readAsString() (shelf) |
| A full handler | Express | Flask and FastAPI | plain PHP, Laravel | net/http | shelf |
Reference
| Call | HTTP | Returns |
|---|---|---|
payments.create({...}) |
POST /v1/payments |
The payment. Takes every create parameter, webhook_url included |
payments.retrieve(id) |
GET /v1/payments/{id} |
The payment, by payment id or your order id |
payments.selectToken(id, token) |
POST /v1/payments/{id}/token |
The whole payment, with the coin the customer picked on your own page: address, amount, QR payload, deadline (details) |
payments.simulate(id, outcome) |
POST /v1/payments/{id}/simulate |
Test keys only: the payment, with the outcome you chose started |
payments.list({status, chain, token, store_id, limit, offset}) |
GET /v1/payments |
A page of payments, newest first |
tokens.list({amount_usd?}) |
GET /v1/tokens |
The tokens your customers can pay with; with an amount, the ones a payment of it offers, with amount_due_usd (details) |
webhooks.get() |
GET /v1/webhook |
The webhook: url (may be null) and secret |
webhooks.set(url) |
PUT /v1/webhook |
The webhook, now pointing at url. Safe to retry |
webhooks.remove() |
DELETE /v1/webhook |
The webhook with url null; the secret is kept |
webhooks.test() |
POST /v1/webhook/test |
The delivery of a signed ping |
webhooks.constructEvent(rawBody, signature, secret?) |
none (local) | The verified event, or a signature error |
checkout.retrieve(checkout_token) |
GET /checkout/{checkout_token} |
The payer's view, without the key (for pages with no server: public checkout API) |
checkout.selectToken(checkout_token, token) |
POST /checkout/{checkout_token}/token |
The payer's view with its coin chosen, without the key |
The same calls in each language:
Method names follow each language: select_token and construct_event in
Python; Get (not retrieve), SelectToken, Set, Remove, Test and
ConstructEvent with a context.Context in Go. Dart also has
checkout.watch, a stream of the payment's
status changes that follows late payments (it polls every 5 seconds: the
fallback for apps that cannot use the socket),
checkout.simulate for a Flutter app's
test payments (no key), and close() for the HTTP
client it made.
A payment's own webhook URL
Pass webhook_url to send one payment's notifications somewhere else
(why), or set the client's default
webhook URL option to do it for every payment that client creates. A payment's
own webhook_url wins over the client's default:
const payitgo = new Payitgo(process.env.PAYITGO_STORE_KEY, {
webhookUrl: "https://eu.acme.example/payitgo/ipn", // every payment of this client
webhookSecret: process.env.PAYITGO_WEBHOOK_SECRET, // the same secret signs them
});
await payitgo.payments.create({ order_id: "EU-77", amount_usd: 20, webhook_url: "https://eu.acme.example/orders/EU-77/ipn" }); // this one only
| Node | Python | PHP | Go | Dart | |
|---|---|---|---|---|---|
| One payment | webhook_url |
webhook_url= |
'webhook_url' |
PaymentParams.WebhookURL |
webhookUrl: |
| Every payment of a client | webhookUrl |
webhook_url= |
'webhook_url' |
payitgo.WithWebhookURL(u) |
webhookUrl: |
Flutter apps
Never ship a secret key in an app. The Dart library's
PayitgoCheckout needs no key: your backend
creates the payment and hands the app its checkout_token, and the app shows
the payment, lets the customer choose the coin and follows its status
(a full screen). Follow it with the
socket (subscribe with the checkout token)
for every change as it happens; checkout.watch polls every 5 seconds, for
apps that cannot use socket.io:
final checkout = PayitgoCheckout(baseUrl: 'https://api.payitgo.co');
await for (final p in checkout.watch(checkoutToken)) {
if (p.isConfirmed) showPaid();
}
By language
Node.js
Install · configuration · errors · payments · webhooks · types · your own payment page · test mode
Python
Install · configuration · errors · payments · webhooks · types · your own payment page · test mode
PHP
Install · configuration · errors · payments · webhooks · types · your own payment page · test mode
Go
Install · configuration · errors · payments · webhooks · types · your own payment page · test mode
Dart
Install · configuration · errors · payments · webhooks · types · your own payment page · Flutter · test mode