> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tribridge.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Tribridge is a crypto payment gateway for Solana and Sui (TON is coming soon). API base URL is https://tribridge.onrender.com. Server-side calls authenticate with the x-api-key header using a tri_test_... key (fully simulated test mode, no real funds) or tri_live_... key (real mainnet payments) — never expose keys client-side. Merchant test mode is simulated, not testnet. Refunds are automatic only (underpaid/overpaid), there is no manual refund endpoint. Always verify webhook HMAC-SHA256 signatures from the X-Tribridge-Signature header before trusting payloads.

# Authentication

> Authenticate server-side requests with your API key and verify inbound webhooks with HMAC signatures.

## API key header

Every server-side API request is authenticated with your **API key** sent in the `x-api-key` header:

```
x-api-key: tri_test_9f3a1c7e8b2d4f6a0c1e3b5d7f9a2c4e
```

Which key to use:

| Situation | Key |
| - | - |
| Building, testing, validating webhooks | `tri_test_...` (simulated, no real funds) |
| Production traffic | `tri_live_...` (real mainnet payments) |

Using the wrong key is the most common cause of `401 Unauthorized` — a live key on a test payment (or vice versa) will not behave as expected.

<Note>
  **Public resources need no key.** Authentication is only required for secret API resources (creating payments, managing webhooks, reading your dashboard). Public, read-only resources — such as fetching the status of a payment by its ID on the hosted checkout — do **not** require an API key:

  ```bash No key required theme={null}
  curl -X GET https://tribridge.onrender.com/payments/checkout/<PAYMENT_ID>
  ```
</Note>

## Verifying webhooks

Tribridge signs every webhook it sends using your endpoint's **webhook secret** (the one returned once when you created the endpoint). The signature arrives in the `X-Tribridge-Signature` header as `sha256=<hmac>`, alongside a timestamp:

```
X-Tribridge-Signature: sha256=9f3a1c7e8b2d4f6a0c1e3b5d7f9a2c4e
X-Tribridge-Timestamp: 2026-08-25T12:00:00.000Z
Content-Type: application/json
```

<Steps>
  <Step title="Read the raw request body">
    You need the exact bytes Tribridge sent — parse the JSON only *after* verifying. In Express, use `express.raw({ type: 'application/json' })` for the webhook route.
  </Step>

  <Step title="Recompute the HMAC">
    Compute HMAC-SHA256 over the raw body using your endpoint's webhook secret as the key, hex-encoded.
  </Step>

  <Step title="Compare in constant time">
    Strip the `sha256=` prefix from the header and compare with `crypto.timingSafeEqual` (never `===` — it's vulnerable to timing attacks). Reject mismatches with a non-2xx status so Tribridge retries.
  </Step>
</Steps>

```javascript Verify signature (Node.js) theme={null}
const crypto = require("crypto");

const expected = crypto
  .createHmac("sha256", WEBHOOK_SECRET)
  .update(rawBody) // exact bytes received
  .digest("hex");

const provided = req.headers["x-tribridge-signature"].replace("sha256=", "");

const ok = crypto.timingSafeEqual(
  Buffer.from(expected),
  Buffer.from(provided)
);

if (!ok) return res.status(401).send("bad signature");
// safe to JSON.parse(rawBody) and trust it
```

## Troubleshooting 401s

* **Missing header** — the request has no `x-api-key` at all.
* **Wrong key for the mode** — test key against a live flow or vice versa.
* **Revoked keypair** — regenerating keys invalidates the old pair immediately (test *and* live together).
* **Webhook 401 on your side** — your signature check rejected the payload. Re-check that you're hashing the *raw* body with the correct endpoint secret (test and live endpoints have different secrets).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.