Guides
Quick start
This guide walks you through the complete flow of making a cross-border payment with the Nexpay API — from setting up your payee to collecting funds. By the end, you'll have a working integration that creates and processes a payment.
Overview
A typical payment flow follows these steps:
- Create a payee — the recipient of funds.
- Get a quote — check the exchange rate and fees.
- Upload documents — identity and purpose proof for compliance.
- Create a payment — submit the payment with payer and payout details.
- Confirm the payment — move it from
createdto processing. - Initiate checkout — redirect the payer to pay.
- Track the status — monitor the payment until completion.
Step 1: Set up your API key
All requests require an API key in the Authorization header. If you haven't created one yet, follow the API keys guide.
Every example below uses this header:
const headers = {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
};
Step 2: Create a payee
A payee is the entity receiving the funds — for example, a university. You only need to do this once per recipient.
const payeeResponse = await fetch('https://api.nexpay.com/v2/payees', {
method: 'POST',
headers,
body: JSON.stringify({
"name": "University of Sydney",
"countryCode": "AU",
"currencyCode": "AUD"
}),
});
const payee = await payeeResponse.json();
console.log('Payee ID:', payee.id); // e.g. 42
See: Creating a payee
Step 3: Get a quote
Request a quote to see the exchange rate and available settlement methods. You'll need the payee ID from the previous step:
const quoteResponse = await fetch('https://api.nexpay.com/v2/quotes', {
method: 'POST',
headers,
body: JSON.stringify({
"payeeId": 42,
"amount": 5000,
"currencyCode": "AUD",
"transactionType": "provider"
}),
});
const quote = await quoteResponse.json();
console.log('Quote ID:', quote.id);
console.log('Expires at:', quote.expiresAt);
console.log('Variants:', quote.variants);
Each variant represents a different settlement method with its own rate and fees. Pick the one that works best for your payer:
// Example: select the first variant
const selectedVariant = quote.variants[0];
console.log('Rate:', selectedVariant.payerRate);
console.log('Payer pays:', selectedVariant.totalAmount, selectedVariant.fromCurrency);
console.log('Payee receives:', selectedVariant.toAmount, selectedVariant.toCurrency);
See: FX quotes and rates
Step 4: Upload documents
Payments require compliance documents — a payer identity document and proof of purpose. Upload them before creating the payment:
// Upload payer identity (e.g. passport scan)
const identityForm = new FormData();
identityForm.append('file', passportFile);
const identityResponse = await fetch('https://api.nexpay.com/v2/documents', {
method: 'POST',
headers: { 'Authorization': 'ApiKey your-api-key-here' },
body: identityForm,
});
const identityDoc = await identityResponse.json();
console.log('Identity doc ID:', identityDoc.id);
// Upload purpose proof (e.g. enrollment letter)
const purposeForm = new FormData();
purposeForm.append('file', enrollmentLetterFile);
const purposeResponse = await fetch('https://api.nexpay.com/v2/documents', {
method: 'POST',
headers: { 'Authorization': 'ApiKey your-api-key-here' },
body: purposeForm,
});
const purposeDoc = await purposeResponse.json();
console.log('Purpose doc ID:', purposeDoc.id);
See: Uploading documents
Step 5: Create the payment
Now bring it all together — create a payment with the quote, payer details, and uploaded documents:
const paymentResponse = await fetch('https://api.nexpay.com/v2/payments', {
method: 'POST',
headers: {
...headers,
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"transactionType": "provider",
"data": {
"quoteId": quote.id,
"selectedQuoteVariantId": 1,
"countryCode": "AU",
"purpose": "undergraduate",
"studentInfo": {
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com"
},
"payerDetails": {
"payerType": "parent",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane.doe@example.com",
"phone": "+61412345678",
"addressLine1": "123 Main Street",
"city": "Sydney",
"state": "NSW",
"postcode": "2000",
"countryCode": "AU"
},
"payouts": [
{
"purposeProofDocumentId": purposeDoc.id,
"reference": "INV-2026-001"
}
],
"payerIdentityDocumentId": identityDoc.id
}
}),
});
const payment = await paymentResponse.json();
console.log('Payment ID:', payment.id);
console.log('Status:', payment.status); // "created"
Idempotency required
Always include an Idempotency-Key header when creating payments. This prevents duplicate payments if you need to retry. See Idempotency.
See: Creating a payment
Step 6: Confirm the payment
The payment starts in created status. Confirm it to begin processing:
const confirmResponse = await fetch(`https://api.nexpay.com/v2/payments/${payment.id}/confirm`, {
method: 'POST',
headers,
});
const confirmed = await confirmResponse.json();
console.log('Status:', confirmed.status); // moves to processing
Step 7: Initiate checkout
Redirect the payer to a hosted checkout page to collect their funds:
const checkoutResponse = await fetch(`https://api.nexpay.com/v2/payments/${payment.id}/checkout`, {
method: 'POST',
headers,
body: JSON.stringify({
"gateway": "checkout",
"returnUrl": "https://yourapp.com/payments/status"
}),
});
const checkout = await checkoutResponse.json();
// Redirect the payer's browser to this URL
console.log('Checkout URL:', checkout.redirectUrl);
Step 8: Track the status
After the payer completes checkout, poll the status to confirm the payment was successful:
const statusResponse = await fetch(`https://api.nexpay.com/v2/payments/${payment.id}/checkout/callback`, {
method: 'GET',
headers,
});
const status = await statusResponse.json();
console.log('Payment status:', status.status);
The payment will move through these statuses as it's processed:
created → ready-to-collect → collected → ready-to-trade → traded → ready-to-pay → paid
Once the status reaches paid, the funds have been delivered to the payee.
Complete example
Here's the entire flow in one script:
const API = 'https://api.nexpay.com/v2';
const headers = {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
};
// 1. Create payee (or use an existing one)
const payee = await fetch(`${API}/payees`, {
method: 'POST', headers,
body: JSON.stringify({
name: 'University of Sydney', countryCode: 'AU', currencyCode: 'AUD',
}),
}).then(r => r.json());
// 2. Get quote
const quote = await fetch(`${API}/quotes`, {
method: 'POST', headers,
body: JSON.stringify({
payeeId: payee.id, amount: 5000, currencyCode: 'AUD', transactionType: 'provider',
}),
}).then(r => r.json());
// 3. Upload documents
const uploadDoc = async (file) => {
const form = new FormData();
form.append('file', file);
return fetch(`${API}/documents`, {
method: 'POST',
headers: { 'Authorization': 'ApiKey your-api-key-here' },
body: form,
}).then(r => r.json());
};
const identityDoc = await uploadDoc(passportFile);
const purposeDoc = await uploadDoc(enrollmentLetterFile);
// 4. Create payment
const payment = await fetch(`${API}/payments`, {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': crypto.randomUUID() },
body: JSON.stringify({
transactionType: 'provider',
data: {
quoteId: quote.id,
selectedQuoteVariantId: 1,
countryCode: 'AU',
purpose: 'undergraduate',
studentInfo: {
firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com',
},
payerDetails: {
payerType: 'parent', firstName: 'Jane', lastName: 'Doe',
email: 'jane.doe@example.com', phone: '+61412345678',
addressLine1: '123 Main Street', city: 'Sydney',
state: 'NSW', postcode: '2000', countryCode: 'AU',
},
payouts: [{
purposeProofDocumentId: purposeDoc.id, reference: 'INV-2026-001',
}],
payerIdentityDocumentId: identityDoc.id,
},
}),
}).then(r => r.json());
// 5. Confirm
await fetch(`${API}/payments/${payment.id}/confirm`, { method: 'POST', headers });
// 6. Checkout
const checkout = await fetch(`${API}/payments/${payment.id}/checkout`, {
method: 'POST', headers,
body: JSON.stringify({ gateway: 'checkout', returnUrl: 'https://yourapp.com/status' }),
}).then(r => r.json());
console.log('Redirect payer to:', checkout.redirectUrl);
Next steps
- Learn about payment statuses to handle every stage of the lifecycle.
- Set up error handling to gracefully manage failures.
- Use lookup data to build dynamic payment forms with the correct countries, purposes, and payer types.
- Track commissions earned on your payments.