Host-to-Host API
Build your own checkout.
Pure REST primitives + HMAC-signed webhooks. Bring your own frontend, render your own payment flow, control every part of the experience. Same Paymos backend, full control over the surface.

How it works
Three calls. Your UI in the middle.
Create the invoice from your backend, render the payment surface yourself, receive a signed event when the payment confirms. The boundary stays clean.
- 1
Create the invoice
POST to /v1/invoices from your backend. Pass the amount, the currency, your own external order ID. Get back the invoice ID and a payment address.
- 2
Render your own UI
Show the address, the QR, the timer — however your product looks. The customer pays from any wallet they already use.
- 3
Receive the signed webhook
Paymos POSTs an HMAC-signed event to your endpoint when the payment confirms. Verify the signature, mark the order paid, return 200.
Try every call before you ship
The dashboard Playground fires real sandbox requests with your test API key. Pick the endpoint, fill the params, hit Send — see the live HMAC signature, the headers, the response. No Postman, no curl, no copy-paste from the docs.

Interface control
When the hosted page isn't enough
For teams that build their own payment form over the API — pixel-perfect to their brand and wired into their own systems. Host-to-host is what you reach for when no ready-made surface fits.
Full surface control
Render the wallet picker, the QR, the status updates yourself. Your design system, your interaction language, your brand.
Native to any stack
Node, Python, PHP, Go, Ruby, Java, .NET — anything that speaks HTTP works. No SDK lock-in.
Signed webhooks with retries
HMAC-signed payloads, at-least-once delivery, exponential backoff retries. Verify on your side, deduplicate on your side.
Sandbox environment
Test mode lives next to production. Same endpoints, isolated data, no real money moves.
What you control
You render the UI. We watch the chain.
The boundary is clear: your frontend handles every pixel the customer sees. Our infrastructure handles wallet derivation, chain monitoring, confirmation depth, and settlement.
Your UI
Wallet picker, network picker, address display, QR generation, status feedback — all yours to design.
Your flow
Sequence the steps however your product needs. Bundle checkout into onboarding, split it across screens, gate it behind authentication.
Your brand
Paymos never appears in the customer's URL or visual frame. The payment surface is fully white-labelled.
Your settlement
Withdraw to your treasury wallet on your schedule. Same balance ledger every other Paymos surface settles into.
Get started
Same backend, no SDK to learn
Create an invoice via REST, poll for status changes or subscribe to webhooks, render whatever UI fits. Nine language samples in the docs, identical signature scheme across endpoints.
Read docsimport { Paymos, externalOrderId } from '@paymos/sdk';
const paymos = new Paymos({
apiKey: process.env.PAYMOS_API_KEY,
apiSecret: process.env.PAYMOS_API_SECRET,
});
const invoice = await paymos.invoices.create({
projectId: 'prj_xxxxxxxxxxxx',
amount: '100.00',
currency: 'USD',
externalOrderId: externalOrderId('order'),
clientId: 'customer-456',
});
console.log(invoice.invoiceId, invoice.paymentUrl);import os
from paymos import Paymos
paymos = Paymos(
api_key=os.environ["PAYMOS_API_KEY"],
api_secret=os.environ["PAYMOS_API_SECRET"],
)
invoice = paymos.invoices.create(
project_id="prj_xxxxxxxxxxxx",
amount="100.00",
currency="USD",
external_order_id="order-123",
client_id="customer-456",
)
print(invoice["invoice_id"], invoice["payment_url"])<?php
use Paymos\Client;
use Paymos\ClientConfig;
use Paymos\IdempotencyKey;
$paymos = new Client(new ClientConfig(
getenv('PAYMOS_API_KEY'),
getenv('PAYMOS_API_SECRET')
));
$invoice = $paymos->invoices()->create(array(
'project_id' => 'prj_xxxxxxxxxxxx',
'amount' => '100.00',
'currency' => 'USD',
'external_order_id' => IdempotencyKey::externalOrderId('order'),
'client_id' => 'customer-456',
));
echo $invoice['invoice_id'] . ' ' . $invoice['payment_url'];package main
import (
"context"
"fmt"
"os"
paymos "github.com/Paymos-labs/go-sdk/v2"
)
func main() {
client, err := paymos.NewClient(os.Getenv("PAYMOS_API_KEY"), os.Getenv("PAYMOS_API_SECRET"))
if err != nil {
panic(err)
}
invoice, err := client.Invoices.Create(context.Background(), paymos.CreateInvoiceParams{
ProjectID: "prj_xxxxxxxxxxxx",
Amount: "100.00",
Currency: "USD",
ExternalOrderID: "order-123",
ClientID: stringPointer("customer-456"),
})
if err != nil {
panic(err)
}
fmt.Println(invoice.InvoiceID, invoice.PaymentURL)
}
func stringPointer(value string) *string { return &value }using Paymos;
using var paymos = new PaymosClient(
Environment.GetEnvironmentVariable("PAYMOS_API_KEY")!,
Environment.GetEnvironmentVariable("PAYMOS_API_SECRET")!);
var invoice = await paymos.Invoices.CreateAsync(new CreateInvoiceRequest(
ProjectId: "prj_xxxxxxxxxxxx",
Amount: "100.00",
Currency: "USD",
ExternalOrderId: "order-123",
ClientId: "customer-456"));
Console.WriteLine($"{invoice.InvoiceId} {invoice.PaymentUrl}");import io.paymos.CreateInvoiceRequest;
import io.paymos.Invoice;
import io.paymos.PaymosClient;
PaymosClient paymos = new PaymosClient(
System.getenv("PAYMOS_API_KEY"),
System.getenv("PAYMOS_API_SECRET"));
Invoice invoice = paymos.invoices.create(
CreateInvoiceRequest.builder()
.projectId("prj_xxxxxxxxxxxx")
.amount("100.00")
.currency("USD")
.externalOrderId("order-123")
.clientId("customer-456")
.build());
System.out.println(invoice.invoiceId() + " " + invoice.paymentUrl());require 'paymos'
paymos = Paymos::Client.new(
api_key: ENV.fetch('PAYMOS_API_KEY'),
api_secret: ENV.fetch('PAYMOS_API_SECRET')
)
invoice = paymos.invoices.create(
project_id: 'prj_xxxxxxxxxxxx',
amount: '100.00',
currency: 'USD',
external_order_id: 'order-123',
client_id: 'customer-456'
)
puts "#{invoice.invoice_id} #{invoice.payment_url}"use paymos::{CreateInvoiceRequest, PaymosClient};
let paymos = PaymosClient::new(
std::env::var("PAYMOS_API_KEY")?,
std::env::var("PAYMOS_API_SECRET")?,
)?;
let invoice = paymos
.invoices()
.create(&CreateInvoiceRequest {
project_id: "prj_xxxxxxxxxxxx".to_owned(),
amount: "100.00".to_owned(),
currency: "USD".to_owned(),
external_order_id: "order-123".to_owned(),
network: None,
allow_multiple_payments: None,
customer_fee_percent: None,
client_id: Some("customer-456".to_owned()),
})
.await?;
println!("{} {}", invoice.invoice_id, invoice.payment_url);One signing scheme
HMAC-SHA256 with a shared secret. Same scheme for invoice creation, status polling, withdrawal, webhook verification — one auth pipeline to maintain.
Platform integration
Multi-project accounts, scoped API keys, idempotent invoice creation via external_order_id. Build the checkout your own way — the API stays the same.
Who uses Host-to-Host
For products with a dedicated payment interface
Anywhere the hosted UI is too constrained — and the business has the engineering team to build their own. Crypto exchanges, custodial wallets, trading platforms, on-ramps.
Crypto exchanges
Run deposits as a native experience inside your trading UI, not as a redirect to a third party.
Custodial wallets
Top-up flows that live entirely inside your wallet app. No browser handoff, no out-of-process step.
Trading platforms
Margin top-ups, deposit reconciliation, multi-account settlement — all driven by the same REST primitives.
White-label platforms
Resell Paymos under your own brand. Your customers never see our name; you handle the relationship.
Pricing
1.0% per settled invoice. Negotiable at scale.
Same baseline as every Paymos surface. High-volume platforms qualify for custom pricing — talk to the founder.
See pricing