Skip to content

Agent Quickstart

Give this page to a coding agent when you want it to add FinCobra Checkout to an existing app.

This guide describes the standard hosted checkout integration. The agent should add the frontend checkout flow, create invoices from the merchant server, redirect customers to the hosted paymentUrl, verify webhooks, and update orders from the current invoice state.

Continuing without an agent? Start with Authentication.

Agent prompt

text
Integrate FinCobra Checkout using the hosted payment page.

Use the frontend for the customer checkout flow and the backend for all FinCobra API calls. Never expose the FinCobra API key or webhook signing secret to browser, mobile, or client-side code.

Required behavior:
1. Add server-side configuration for FINCOBRA_CHECKOUT_API_KEY and FINCOBRA_CHECKOUT_WEBHOOK_SECRET.
2. Add a frontend checkout action that calls the merchant backend to start checkout for the current order.
3. In the merchant backend, create a FinCobra invoice with POST https://fincobra.com/api/checkout/invoices.
4. Store the returned invoice id and paymentUrl with the local order.
5. Return paymentUrl to the frontend and redirect the customer there.
6. Add frontend handling for the return page or order page so the customer can see pending, paid, expired, or voided checkout state from the merchant backend.
7. Add a webhook endpoint that verifies X-Checkout-Signature with HMAC-SHA256 over the raw JSON request body.
8. After a valid webhook, fetch GET https://fincobra.com/api/checkout/invoices/:id from the server and update the local order from the current invoice status.
9. Treat confirmed and paid_out_of_band as paid. Keep payment_detected pending unless this business accepts unconfirmed crypto payments.

Use these docs as the source of truth:
- Overview: https://fincobra.com/docs/checkout/
- Invoices: https://fincobra.com/docs/checkout/invoices.html
- Webhooks: https://fincobra.com/docs/checkout/webhooks.html
- API Reference: https://fincobra.com/docs/checkout/api-reference.html

Integration shape

The integration has both frontend and backend work:

App layerResponsibility
FrontendStart checkout by calling the merchant backend, redirect to paymentUrl, and render local order status after the customer returns.
BackendStore secrets, create FinCobra invoices, store invoice IDs, verify webhooks, fetch current invoice state, and update local orders.
FinCobra hosted pageCollect payment through the hosted checkout page and show live payment status to the customer.

Do not call FinCobra merchant endpoints directly from frontend code. The browser should only talk to the merchant backend and visit the hosted paymentUrl.

Merchant setup

Before code changes, the merchant should complete these dashboard steps:

  1. Configure at least one payment method.
  2. Set invoice timing, issuer name, and redirect URL defaults.
  3. Create a Checkout API key.
  4. Create a webhook signing secret.
  5. Add the production webhook URL.

Use these server-side environment variables:

text
FINCOBRA_CHECKOUT_API_KEY=fc_live_...
FINCOBRA_CHECKOUT_WEBHOOK_SECRET=...
FINCOBRA_CHECKOUT_BASE_URL=https://fincobra.com

Frontend checkout flow

Add a checkout button or action that calls the merchant backend for the current order:

javascript
async function startCheckout(orderId) {
  const response = await fetch(`/api/orders/${orderId}/checkout`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
  });

  if (!response.ok) {
    throw new Error('Unable to start checkout');
  }

  const checkout = await response.json();
  window.location.assign(checkout.paymentUrl);
}

The merchant backend response should contain the hosted paymentUrl, not the FinCobra API key.

The hosted page redirects to the exact redirectUrl after confirmed or paid_out_of_band; no invoice params are appended.

After the customer returns to the merchant app, show the local order state from the merchant backend. Use confirmed and paid_out_of_band as paid states. Show payment_detected as pending unless the business accepts unconfirmed crypto payments.

Backend invoice creation

Create invoices from the merchant server. Store the local order ID in merchantReference and metadata so webhook handling can reconcile the invoice.

bash
curl -X POST https://fincobra.com/api/checkout/invoices \
  -H "X-Api-Key: fc_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "amountUsd": 49.99,
    "productName": "Pro Plan - Monthly",
    "merchantReference": "order_123",
    "customerEmail": "buyer@example.com",
    "metadata": {
      "orderId": "order_123"
    }
  }'

Use the response like this:

FieldRequired action
idStore with the local order as the FinCobra invoice ID.
paymentUrlRedirect the customer to this URL.
statusStore for admin display and reconciliation.
paymentSummaryStore or read when handling partial payment and overpayment states.

For standard hosted checkout, do not build custom payment instructions from paymentOptions[]. Redirect to paymentUrl.

Webhook handling

FinCobra sends POST requests to the configured webhook URL with X-Checkout-Signature.

The signature is an HMAC-SHA256 hex digest of the raw JSON request body using the webhook signing secret.

javascript
import crypto from 'node:crypto';

function verifyFinCobraSignature(rawBody, signature, secret) {
  if (typeof signature !== 'string') {
    return false;
  }

  if (!/^[0-9a-f]{64}$/i.test(signature)) {
    return false;
  }

  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  const signatureBuffer = Buffer.from(signature, 'hex');
  const expectedBuffer = Buffer.from(expected, 'hex');

  return (
    signatureBuffer.length === expectedBuffer.length &&
    crypto.timingSafeEqual(signatureBuffer, expectedBuffer)
  );
}

Use payload.invoice.id from the webhook body, then fetch the latest invoice before updating the order.

After verifying the signature, fetch the latest invoice before changing order state:

bash
curl https://fincobra.com/api/checkout/invoices/a1b2c3d4-1111-4222-8333-abcdefabcdef \
  -H "X-Api-Key: fc_live_..."

Webhook delivery is at-least-once. Make the local order update idempotent.

Status mapping

FinCobra invoice statusMerchant order action
awaiting_paymentKeep pending.
partially_paidKeep pending and review paymentSummary.remainingAmountUsd.
payment_detectedKeep pending unless the business accepts detected but unconfirmed payment.
confirmedMark paid and fulfill if not already fulfilled.
paid_out_of_bandMark paid and store the payment note for reconciliation.
expiredMark checkout expired and let the customer start a new checkout.
voidedStop accepting payment for this invoice.

Use paymentCoverage and paymentSummary for partial payment and overpayment operations. Treat confirmed as the default fulfillment trigger.

Implementation checklist

  • Keep the API key and webhook secret server-side.
  • Create invoices from the merchant backend, not the browser.
  • Save the FinCobra invoice ID on the local order.
  • Redirect customers to paymentUrl.
  • Verify webhook signatures using the raw request body.
  • Fetch current invoice state before updating orders.
  • Make webhook processing idempotent.
  • Add tests for invoice creation, webhook signature rejection, duplicate webhook delivery, and status-to-order mapping.