Build with Mesh

One platform for payments, marketplace APIs, and embedded commerce. Use our REST APIs or SDKs—auth, escrow, and stablecoin payments included.

SDKs & libraries

Official SDKs for Ruby, iOS, Android, JavaScript, and PHP.

API examples

Payments (Mesh Pay) and Marketplace each have their own APIs. Below: one example each. Full reference on the product pages.

Payments – Create a charge

bash
curl https://api.mesh.com/v1/charges \
  -u sk_live_xxx: \
  -d amount=5000 \
  -d currency=usd \
  -d wallet_id=wallet_xxx

Mesh Payments → for more examples and the Ruby SDK.

Marketplace – List listings (public)

bash
curl "https://api.mesh.com/listings/search?limit=20" \
  -H "Content-Type: application/json"

Mesh Marketplace → for authenticated endpoints and the iOS SDK.

Quickstart

  1. Set up Supabase Auth – Create a project at supabase.com, enable Auth, and configure your client (email/password, OAuth, etc.).
  2. Get your JWT – After sign-in, Supabase returns an access_token. Use it as Authorization: Bearer <token>.
  3. Create or fetch your profile – Call POST /users with profile data. The endpoint is idempotent by authProviderId.
  4. Start building – Listings, offers, transactions, and escrow are available. See the documentation and API reference for full details.

Auth flow

Mesh uses Supabase Auth for identity. The mesh-core API validates JWTs issued by Supabase.

1. Client signs in with Supabase (email/password, OAuth, etc.)
2. Supabase returns a JWT (access_token)
3. Client sends requests with: Authorization: Bearer <token>
4. mesh-core validates the JWT and maps 'sub' to authProviderId
5. On first request, POST /users creates the internal User profile
Public vs protected routes – Some routes (e.g. GET /listings) are public. Protected routes require a valid JWT; invalid or missing tokens return 401 Unauthorized.

SDK examples

Use the API with standard fetch or any HTTP client. All requests use JSON; auth is via Bearer token.

List public listings

const res = await fetch(`${API_URL}/listings/search?limit=20`);
const { data } = await res.json();

Create user profile (idempotent)

const res = await fetch(`${API_URL}/users`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    displayName: 'Jane',
    email: 'jane@example.com',
  }),
});

Submit an offer

const res = await fetch(`${API_URL}/offers`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    listingId: 'listing-uuid',
    message: 'I can pick up today',
    amountCents: 5000,
  }),
});

Generic API helper (recommended)

async function api(path, { method = 'GET', body, token } = {}) {
  const res = await fetch(`${API_URL}${path}`, {
    method,
    headers: {
      'Content-Type': 'application/json',
      ...(token && { Authorization: `Bearer ${token}` }),
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!res.ok) throw new Error(await res.text());
  return res.status === 204 ? {} : res.json();
}

// Usage
const listings = await api('/listings/search?limit=10');
const user = await api('/users', { method: 'POST', body: { displayName: 'Jane' }, token });

Escrow flow (summary)

Escrow uses Stripe Payment Intents. After offer acceptance, the buyer funds escrow; funds are released only after both parties confirm the exchange.

  • POST /escrow/create-payment-intent with transactionId → returns clientSecret
  • Confirm payment client-side with Stripe.js
  • Webhook updates transaction to ESCROW_FUNDED
  • Schedule exchange, both confirm → POST /escrow/release/:transactionId

See documentation, API Docs, and the mesh-core docs/escrow-flow.md for full details.

Resources