Accept 3DS authentication

Accepts a 3D Secure authentication request with cryptographic signatures.

This endpoint is used to confirm a 3DS authentication after the user has
reviewed the transaction details in their wallet application. The request
must include valid cryptographic signatures proving the user's consent.

Example with Ethersjs:

const wallet = ethers.Wallet.createRandom();
const types = {
  Authenticate: [{ name: 'id', type: 'string' }],
};
const domain = {
  name: 'Kulipa Wallet Authentication',
  version: '1',
  chainId: 1, // this is the chain ID of the wallet network
};
const message = {
  id: '3ds-e259ee22-f857-444d-9c38-e0bf2ee669e3', // the 3DS authentication ID
};

const signature = await wallet.signTypedData(domain, types, message);

Example with ECDSA signature (when signing from the user wallet is not possible):

Make sure to use the correct private key and passphrase from the public key you shared with Kulipa.

const crypto = require('crypto');
const canonicalize = require('canonicalize');

const payload = {
  primaryType: 'Authenticate',
  message: {
    id: '3ds-e259ee22-f857-444d-9c38-e0bf2ee669e3'
  }
};

const canonicalizedPayload = canonicalize(payload);
const sign = crypto.createSign('SHA256');
sign.update(canonicalizedPayload);
sign.end();

const signature = sign.sign({
  key: privateKey, // your private key
  format: 'pem',
  type: 'pkcs8',
  passphrase: 'your-passphrase', 
}, 'hex');

Example with Solana kit:

const keys = await generateKeyPair();
const address = await getAddressFromPublicKey(keys.publicKey);
const validTypedData = {
  cardAuthenticationId: '3ds-e259ee22-f857-444d-9c38-e0bf2ee669e3',
  purpose: 'Card 3DS Authentication',
  organisation: 'Kulipa',
  userId: 'usr-595f5f00-8471-4676-90b0-61a9277e2f78',
  nonce: getUnixTime(new Date()), // we validate the nonce is within +/- 5 minutes of the current timestamp to allow for server drift
  wallet: address,
};
const structCodec = getStructCodec([
  ['organisation', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['userId', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['purpose', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['nonce', getU64Codec()],
  ['wallet', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['cardAuthenticationId', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
]);
const encodedData = structCodec.encode(validTypedData);
const signedBytes = await signBytes(keys.privateKey, encodedData);
const signature = getBase58Decoder().decode(signedBytes);
console.log(signature);

For more details about the 3DS process, see the 3DS documentation.

Path Params
string
required
length between 40 and 40

The UUID of the card authentication

Body Params

Data to be sent to accept 3DS authentication.

signatures
array of strings

The signatures of the 3DS authentication.

signatures
typedData
object

The typed structured data of the 3DS authentication.

Responses
204

3DS authentication successfully accepted

400

The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

401

Although the HTTP standard specifies "unauthorized", semantically this response means "unauthenticated". That is, the client must authenticate itself to get the requested response.

403

The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. Unlike 401 Unauthorized, the client's identity is known to the server.

429

The user has sent too many requests in a given amount of time ("rate limiting").

500

The server has encountered a situation it does not know how to handle.

502

This error response means that the server, while working as a gateway to get a response needed to handle the request, got an invalid response.

503

The server is not ready to handle the request. Common causes are a server that is down for maintenance or that is overloaded.

504

This error response is given when the server is acting as a gateway and cannot get a response in time.

Language
Credentials
Header