Developer Docs

FAQ

Frequently asked questions about the BSync API.

Common integration questions and answers.

Payment stuck in "waiting" / pending

Symptom: status is pending, matchStatus is waiting.

Causes:

  • Customer has not completed payment on the hosted checkout page.
  • Customer paid but SMS has not been matched yet (usually seconds).
  • Payment has expired.

Actions:

  1. Check expiresAt — if past, status will become expired.
  2. Ask customer to complete payment at checkoutUrl.
  3. Wait for PAYMENT_MATCHED or PAYMENT_PAID webhook.
  4. If stuck > 30 minutes, check BSync Dashboard for the payment.

Webhook not received

Symptom: Payment completed but no webhook delivered.

Checks:

  1. Webhook URL configured in Dashboard? Must be HTTPS in production.
  2. Endpoint returning 2xx? Non-2xx triggers retries, then dead_letter.
  3. Firewall blocking BSync IPs? Ensure your server accepts inbound POST.
  4. Using ngrok for local testing? Tunnel must be active.
  5. Check webhook delivery logs in the Dashboard.

Testing: Send a sample payload from the Postman Webhooks folder.

409 Conflict on create

Symptom: IDEMPOTENCY_CONFLICT when creating a payment.

Cause: Same Idempotency-Key used with a different request body.

Fix:

  • If retrying the same order: send the exact same body.
  • If creating a new order: use a new idempotency key (order-${newOrderId}).

See Idempotency.

Payment expired

Symptom: status is expired or checkout returns 410 CHECKOUT_EXPIRED.

Cause: Customer did not pay within the expiry window (default: 30 minutes).

Fix: Create a new Payment Intent. Do not reuse the expired paymentId.

const newPayment = await bsync.paymentIntents.create({
  amount: 150,
  currency: "EGP",
  externalOrderId: "ORD-42-retry",
  redirectDelay: 3,
});

Review required

Symptom: matchStatus is review_required, webhook PAYMENT_REVIEW_REQUIRED received.

Cause: BSync detected an anomaly (amount mismatch, duplicate, etc.) requiring manual review.

Actions:

  1. Do not fulfill the order yet.
  2. Wait for PAYMENT_REVIEW_APPROVED or PAYMENT_REVIEW_REJECTED webhook.
  3. Inform the customer that payment is being verified.
  4. Check the BSync Dashboard for review status.

Payment already paid

Symptom: 409 PAYMENT_ALREADY_PROCESSED when trying to cancel or modify.

Cause: Payment is already paid. Cannot cancel or recreate.

Actions:

  • If order already fulfilled: no action needed.
  • If duplicate create attempt: check idempotency key — the original payment succeeded.
  • Verify via getStatus() and webhook history.

How to retry a failed API call

The SDK retries automatically for network errors, 5xx, and 429. For manual retries:

await bsync.paymentIntents.create(
  { amount: 150, currency: "EGP", externalOrderId: "ORD-42", redirectDelay: 3 },
  { idempotencyKey: "order-ORD-42" }
);

Use the same idempotency key to safely retry. See Idempotency.

How to rotate API keys

  1. Dashboard → API Keys → Create new key.
  2. Update BSYNC_API_KEY in your deployment.
  3. Deploy all services.
  4. Revoke the old key.
  5. Monitor logs for 401 errors.

See Authentication and Security.

Can I use the API from the browser?

No. API keys must never be exposed client-side. All BSync API calls must go through your server.

What currencies are supported?

Currently EGP (Egyptian Pound) is the default and primary currency. See OpenAPI PaymentIntentCreateRequest for the current default.

How do I test without real money?

Use a bsync_test_* API key. All operations run in sandbox mode with no real transfers. See Testing.

Where is the full API reference?

  • Interactive docs: /docs/api-reference
  • OpenAPI spec: BSync-Server/openapi/openapi.yaml
  • Internal reference: project-documentation/07-developer-api.md

Was this page helpful?

faq

Command Palette

Search for a command to run...