Wallet Infrastructure
Wallet Infrastructure
Platform & Onboarding

Integration Walkthrough

One customer, from wallet to confirmed payment.

Integration
YouCreate customerPOST /v1/customers
id
CustomerRegister passkeyWebAuthn
registration
Wallet InfrastructureProvision walletsaddresses
funds
Wallet InfrastructureReceive and senddeposit.* · transaction.*
webhooks
YouReconcileconfirmed

Architecture

Keep your API key on your server. Your app handles the customer and their passkey; your server calls Wallet Infrastructure and processes notifications.

PartDoes
Your appRegisters the customer's passkey and asks them to approve payments.
Your serverHolds the API key, calls the API and keeps your own records.
Your webhook endpointVerifies, 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.

On this page