Migrate from Triple-A
Move from Triple-A to CoinCircuit: swap OAuth2 for an API key, update webhook signing, and map every field.
Open the interactive version or read this guide as markdown.
Triple-A and CoinCircuit are both licensed crypto payment platforms — you create a payment, the customer sends crypto to an address, and your server receives a notification when it settles. The integration model is similar, but the two platforms differ significantly in authentication and webhook signing. Triple-A uses OAuth2 client credentials for every API call; CoinCircuit uses a single static API key. Triple-A signs notifications with a per-payment secret; CoinCircuit signs with a global webhook secret using HMAC-SHA256 on the raw request body.
Concept mapping
| Triple-A | CoinCircuit | Notes |
|---|---|---|
| OAuth2 Bearer token | x-api-key header |
One static key replaces the token flow entirely. |
client_id + client_secret |
API key | Generate once in the dashboard under Developer > API Keys. |
merchant_key |
— | CoinCircuit keys are already scoped to your account. |
Payment (type: triplea) |
Payment (checkout session) | Redirect the customer to checkoutUrl. |
Invoice (type: invoice) |
Invoice | Itemised billing with a hosted pay link. |
Widget (type: widget) |
Checkout session | CoinCircuit's hosted checkout embeds the same way. |
notify_url |
webhookUrl |
Per-payment webhook URL. |
notify_secret |
Webhook secret | Set once in the dashboard; CoinCircuit signs all events with it. |
payment_reference |
reference |
Unique ID returned when you create the payment. |
order_id |
metadata.orderId |
Store your internal ID in metadata — it comes back on every event. |
webhook_data |
metadata |
Any extra key-value data passed through to webhooks. |
Payment tier (good / hold / invalid) |
Webhook events | See event mapping in Step 4. |
/api/v2/payout/withdraw/... |
POST /api/v1/payouts |
Save a recipient once, then pay out to it. |
sandbox: true in request body |
Sandbox base URL | Use https://sandbox-api.coincircuit.io with test keys. |
Step 1 — Replace OAuth2 with an API key
Triple-A requires a token exchange before every session. You POST your client_id and client_secret to get a Bearer token, then send it on every subsequent request.
Triple-A
POST https://api.triple-a.io/api/v2/oauth/token
Content-Type: application/x-www-form-urlencoded
client_id=oacid-*****&client_secret=Qi42***&grant_type=client_credentials
{ "access_token": "1ba8***", "token_type": "bearer", "expires_in": 315359999 }
Every subsequent request then sends Authorization: Bearer 1ba8***.
CoinCircuit
Delete the token exchange entirely. Every request sends one static header:
x-api-key: sk_live_your_key
Generate your key in the dashboard under Developer > API Keys. Test keys work against https://sandbox-api.coincircuit.io; live keys work against https://api.coincircuit.io.
Step 2 — Create payments
Triple-A has three payment types in one endpoint: triplea (hosted redirect), widget (embedded), and invoice (invoice link). The merchant_key selects which merchant account receives funds, and notify_secret signs each notification individually.
Triple-A
POST https://api.triple-a.io/api/v2/payment
Authorization: Bearer <token>
Content-Type: application/json
{
"type": "triplea",
"merchant_key": "mkey-ckfhqahxy04g6e4qs6t3f00nl",
"order_currency": "USD",
"order_amount": 10,
"order_id": "TSGA267KL",
"notify_url": "https://your-site.com/webhook",
"notify_secret": "Cf9mx4nAvRuy5vwBY2FCtaKr",
"payer_email": "alice@example.com",
"success_url": "https://your-site.com/success",
"cancel_url": "https://your-site.com/cancel",
"webhook_data": { "order_id": "TSGA267KL" }
}
The response includes hosted_url — redirect the customer there.
CoinCircuit
POST https://api.coincircuit.io/api/v1/payments
x-api-key: sk_live_your_key
Content-Type: application/json
{
"title": "Order TSGA267KL",
"description": "Your order description",
"amount": "10.00",
"currency": "USD",
"customer": { "email": "alice@example.com" },
"webhookUrl": "https://your-site.com/webhook",
"successUrl": "https://your-site.com/success",
"cancelUrl": "https://your-site.com/cancel",
"metadata": { "orderId": "TSGA267KL" }
}
The response includes checkoutUrl — redirect the customer there. CoinCircuit handles exchange rate locking and crypto selection internally.
Field mapping
| Triple-A field | CoinCircuit field | Notes |
|---|---|---|
type |
— | Not needed; CoinCircuit has one payment type. |
merchant_key |
— | Your API key already scopes to your account. |
order_currency |
currency |
NGN or USD. |
order_amount |
amount |
Pass as a string, e.g. "10.00". |
order_id |
metadata.orderId |
Stored in metadata; returned on every webhook. |
notify_url |
webhookUrl |
Per-payment webhook URL. |
notify_secret |
Webhook secret | Set once in the dashboard; no longer per-payment. |
payer_email |
customer.email |
Required. |
payer_name |
customer.firstName + customer.lastName |
Split into two fields. |
payer_phone |
customer.phone |
Optional. |
success_url |
successUrl |
Redirect on successful payment. |
cancel_url |
cancelUrl |
Redirect on cancellation. |
webhook_data |
metadata |
Any key-value data echoed back in webhooks. |
Step 3 — Replace invoices
Triple-A's invoice type (type: invoice) emails the customer a hosted invoice URL. CoinCircuit invoices are line-item based.
Triple-A
{
"type": "invoice",
"merchant_key": "mkey-ckfhqahxy04g6e4qs6t3f00nl",
"order_currency": "USD",
"order_amount": 100,
"order_id": "INV-001",
"invoice_desc": "Consulting services — June",
"notify_payer": true,
"payer_email": "client@example.com",
"payer_name": "Alice Tan"
}
CoinCircuit
Map invoice_desc to description and break the total into items. The reference field replaces order_id.
POST https://api.coincircuit.io/api/v1/invoices
x-api-key: sk_live_your_key
Content-Type: application/json
{
"description": "Consulting services — June",
"currency": "USD",
"expiresAt": "2026-08-01T00:00:00Z",
"reference": "INV-001",
"customer": { "email": "client@example.com", "firstName": "Alice" },
"items": [
{ "name": "Consulting services — June", "quantity": 1, "unitPrice": 100 }
]
}
The response includes invoiceUrl — share it with your customer or embed it in your own email.
Step 4 — Migrate webhooks
Triple-A POSTs to your notify_url when a payment changes tier. Each payment carries its own notify_secret; if omitted, Triple-A auto-generates one and returns it in the create-payment response.
Triple-A notification payload
{
"event": "payment",
"merchant_key": "mkey-ckfhqahxy04g6e4qs6t3f00nl",
"payment_reference": "SDF-453672-PMT",
"status": "good",
"payment_tier": "good",
"order_currency": "USD",
"payment_amount": 10,
"webhook_data": { "order_id": "TSGA267KL" }
}
CoinCircuit webhook handler
CoinCircuit uses a single global webhook secret and signs every event with HMAC-SHA256 on the raw request body, sending the result in the x-coincircuit-signature header.
const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-coincircuit-signature'];
const expected = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
res.sendStatus(200);
});
Use
express.raw()so you verify the exact bytes CoinCircuit signed, before any JSON parsing.
Key signing differences
| Triple-A | CoinCircuit |
|---|---|
Per-payment notify_secret |
Single global webhook secret in the dashboard |
| No documented signature header | x-coincircuit-signature (HMAC-SHA256 hex) |
notify_url per payment |
webhookUrl per payment, or global URL in dashboard |
webhook_data echoed in body |
metadata echoed in every event |
Payment tier mapping
Triple-A status / payment_tier |
CoinCircuit event | Meaning |
|---|---|---|
none |
— | No funds received yet; CoinCircuit omits pre-deposit events. |
short |
transaction.received |
Funds detected on-chain, not yet confirmed. |
hold |
transaction.confirmed |
Transaction confirmed on the blockchain. |
good |
payment.completed |
Payment settled in full — fulfil the order on this event. |
invalid |
payment.expired |
Payment expired or could not be completed. |
| — | payment.partial |
Partial deposit received. |
Fulfil orders on payment.completed (was good in Triple-A). Your order_id from webhook_data is now in metadata and comes back on every event.
Step 5 — Migrate payouts
Triple-A emails the recipient a payout form to collect their wallet address. CoinCircuit saves the recipient once and pays out directly.
Triple-A
POST https://api.triple-a.io/api/v2/payout/withdraw/local/crypto
Authorization: Bearer <token>
Content-Type: application/json
{
"merchant_key": "mkey-ck9e0srok0000zumg7vx3hpkh",
"email": "alice@example.com",
"withdraw_currency": "USDT",
"withdraw_amount": 50,
"order_id": "PAYOUT-001",
"notify_url": "https://your-site.com/webhook"
}
Check balance first with GET /api/v2/payout/balances. Track status with GET /api/v2/payout/withdraw/{payout_reference}. Payout statuses: new → confirm → done (or cancel).
CoinCircuit
POST https://api.coincircuit.io/api/v1/crypto-addresses
x-api-key: sk_live_your_key
Content-Type: application/json
{ "address": "0xRecipientAddress", "chain": "base", "asset": "USDT", "label": "Alice" }
GET https://api.coincircuit.io/api/v1/payouts/fees?asset=USDT&chain=base&amount=50
POST https://api.coincircuit.io/api/v1/payouts
x-api-key: sk_live_your_key
Content-Type: application/json
{
"asset": "USDT",
"chain": "base",
"amount": "50.00",
"recipientId": "crypto-address-id-from-above"
}
Listen for payout.success or payout.failed webhooks. Track status with GET /api/v1/payouts/{id}.
Step 6 — Check payment status
Triple-A: GET https://api.triple-a.io/api/v2/payment/{payment_reference} with Authorization: Bearer <token>.
CoinCircuit:
GET https://api.coincircuit.io/api/v1/payments/reference/{reference}
x-api-key: sk_live_your_key
The reference is returned when you create the payment. To list all payments:
GET https://api.coincircuit.io/api/v1/payments?page=1&size=20
x-api-key: sk_live_your_key
Step 7 — Test in the sandbox
Triple-A activates test mode with a sandbox: true flag in the request body. CoinCircuit uses a separate base URL with test keys instead — no flag needed.
- https://api.triple-a.io/api/v2
+ https://sandbox-api.coincircuit.io/api/v1
Use the Simulate payment button on the sandbox checkout page to trigger outcomes (full, partial, overpayment, AML failure) without moving real funds. See the Sandbox Environment guide for faucet links and testnet details.