Integration Walkthrough
One customer, from wallet to confirmed payment.
POST /v1/customersWebAuthnaddressesdeposit.* · transaction.*confirmedArchitecture
Keep your API key on your server. Your app handles the customer and their passkey; your server calls Wallet Infrastructure and processes notifications.
| Part | Does |
|---|---|
| Your app | Registers the customer's passkey and asks them to approve payments. |
| Your server | Holds the API key, calls the API and keeps your own records. |
| Your webhook endpoint | Verifies, deduplicates and records notifications. |
1. Create the customer
curl -X POST https://api.pilot.shiga.io/v1/customers \
-H 'Authorization: Bearer sk_test_...' \
-H 'Content-Type: application/json' \
-d '{ "reference": "cust_8812" }'Store the id from the response. Every later request about this customer sends it as x-customer-id.
2. Register a passkey on the customer's device
Use WebAuthn with your own domain as the relying party and an ES256 (P-256) key. This example uses @simplewebauthn.
import { startRegistration } from '@simplewebauthn/browser';
const options = await fetch('/passkey/options').then(r => r.json());
const registration = await startRegistration({ optionsJSON: options });
await fetch('/passkey/register', {
method: 'POST',
body: JSON.stringify(registration),
});On your server, verify the registration and send its credential to Wallet Infrastructure:
import { verifyRegistrationResponse } from '@simplewebauthn/server';
const { registrationInfo } = await verifyRegistrationResponse({
response: registration,
expectedChallenge,
expectedOrigin: 'https://your-domain.com',
expectedRPID: 'your-domain.com',
});
const passkeyRegistration = {
credentialId: registrationInfo.credential.id,
credentialPublicKey: Buffer.from(
registrationInfo.credential.publicKey,
).toString('base64url'),
rpId: 'your-domain.com',
origins: ['https://your-domain.com'],
};Send the COSE public key
credentialPublicKey is the COSE key from the verified registration, as
base64url. The browser's publicKey field is a different format and is
refused.
3. Provision the wallets
curl -X POST https://api.pilot.shiga.io/v1/wallets/provision \
-H 'Authorization: Bearer sk_test_...' \
-H 'x-customer-id: <customer id>' \
-H 'Content-Type: application/json' \
-d '{ "passkeyRegistration": { "credentialId": "...", "credentialPublicKey": "...", "rpId": "your-domain.com", "origins": ["https://your-domain.com"] } }'The response lists each wallet with its moduleId, chain, address and status: created, already_exists or failed. Retrying is safe; wallets that exist come back as already_exists.
4. Receive funds
Show the customer their address. Credit them on deposit.confirmed; deposit.detected means the deposit is seen, not final. See Receiving Deposits.
5. Send funds
Quote, have the customer approve with their passkey, and submit. See Sending Payments.
6. Confirm and reconcile
A payment is complete only when its status is confirmed. submitted and pending are not final. See Reliability.