How It Works

Table of Content

Table of Content

Table of Content

API Walkthrough

  1. Core Objects

1.1 Destination

This is what the platform stores after a user links their stablecoin app. It is an opaque reference that Swype resolves internally during payout execution.

{
  "destination_id": "dst_9f3a21",
  "status": "linked",
  "created_at": "2026-01-06T15:12:03Z"
}
Notes:
  • destination_id does not contain chain, asset, or address details.

  • The platform stores destination_id and maps it to its own platform_user_id.

1.2 Payout Request

This is the instruction the platform sends to initiate a payout: pay this linked destination this amount in USD.

{
  "destination_id": "dst_9f3a21",
  "amount": {
    "value": 1250.00,
    "currency": "USD"
  },
  "reference": "creator_payout_2026_01_06"
}
Notes:
  • This is intentionally high-level: no chains, tokens, gas, or addresses.

  • Use an Idempotency-Key header to prevent duplicate payouts on retries.

1.3 Payout

This is the payout object returned by Swype after creation and updated over time as execution progresses.

{
  "payout_id": "po_83k2l1",
  "destination_id": "dst_9f3a21",
  "amount": {
    "value": 1250.00,
    "currency": "USD"
  },
  "status": "submitted",
  "created_at": "2026-01-06T15:14:22Z"
}

Optional fields Swype may include as execution progresses:

{
  "provider": {
    "name": "bridge",
    "provider_payout_id": "prov_72a9d2"
  },
  "tx_hash": "0xabc123..."
}

Notes:
  • The regulated execution partner is the sender of record.

  • tx_hash is included when available, and serves as verifiable proof of execution.

1.4 Webhook Event

Webhooks notify the platform when a payout moves through its lifecycle. Platforms should verify signatures before trusting events.

{
  "id": "evt_1a2b3c",
  "type": "payout.processing",
  "created_at": "2026-01-06T15:15:10Z",
  "data": {
    "payout_id": "po_83k2l1",
    "destination_id": "dst_9f3a21",
    "status": "processing"
  }
}
  1. End-to-End Examples

2.1 Exchange → destination_id

After a user completes the hosted linking flow, the platform exchanges the completed link session for a single opaque destination_id.

This identifier represents the user’s linked payout destination and is what the platform stores and uses for all future payouts. The platform never receives addresses, chains, or asset details.

Example (Node.js):
import fetch from "node-fetch";

async function exchangeLinkSession(linkSessionId) {
  const response = await fetch(
    `https://api.swype.com/v1/link_sessions/${linkSessionId}/exchange`,
    {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.SWYPE_API_KEY}`,
        "Content-Type": "application/json"
      }
    }
  );

  const result = await response.json();

  return {
    destination_id: result.destination_id,
    status: result.status
  };
}
What the platform stores:
platform_user_id destination_id
2.2 Create payout

Then, to initiate a payout, the platform submits a platform-level instruction such as: pay this destination this amount in USD.

Example (Node.js):
import fetch from "node-fetch";
import { v4 as uuidv4 } from "uuid";

async function createPayout(destinationId, amountUsd) {
  const idempotencyKey = uuidv4();

  const response = await fetch("https://api.swype.com/v1/payouts", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.SWYPE_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": idempotencyKey
    },
    body: JSON.stringify({
      destination_id: destinationId,
      amount: {
        value: amountUsd,
        currency: "USD"
      },
      reference: "creator_payout_2026_01_06"
    })
  });

  return response.json();
}
What happens next:
  • Swype resolves destination + chooses route (asset/network/partner)

  • Execution partner executes transfer (sender of record)

  • Swype tracks state + emits lifecycle webhooks

2.3 Webhook handler

Swype sends webhooks to notify the platform of payout status changes
(e.g. payout.processing, payout.completed, payout.failed). The platform verifies the webhook signature before trusting the event.

Example (Node.js):
function verifySignature(payload, signature, secret) {
  if (!signature) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");

  // Prevent timingSafeEqual from throwing on length mismatch
  if (signature.length !== expected.length) return false;

  return crypto.timingSafeEqual(
    Buffer.from(signature, "utf8"),
    Buffer.from(expected, "utf8")
  );
}

app.post("/webhooks/swype", (req, res) => {
  const signatureHeader = req.headers["swype-signature"];
  const signature = Array.isArray(signatureHeader) ? signatureHeader[0] : signatureHeader;

  const payload = req.body;

  if (!verifySignature(payload, signature, process.env.SWYPE_WEBHOOK_SECRET)) {
    return res.status(400).send("Invalid signature");
  }

  const event = JSON.parse(payload.toString("utf8"));

  switch (event.type) {
    case "payout.processing":
      break;
    case "payout.completed":
      break;
    case "payout.failed":
      break;
  }

  res.status(200).send("OK");
});