[#1392] What is the correct timestamp format for approve order via sbpay API

Migrated from Redmine #1392 | Author: JM Kuizon
Status: Feedback | Priority: Immediate, there is BUG! | Created: 2025-03-04


Hi,

I am currently calling this method/API: https://app.sbpay.me/en/api-documentation#post_/api/order/{id}/approve via custom payment, but I am encountering this error message (Please see attached screenshot):

I am using Stripe as the payment method internally.

This is the body that I received with the custom payment:


{
  body: {
    order_id: '663',
    amount: '300',
    currency: 'SGD',
    customer_id: '286',
    save_payment_method: '0',
    return_url: 'https://app.sbpay.me/return/symphdev/custom/order/663/db6fcbd5e75e680148530448d1e5462d499b127bd0aa6bded733670da4eb30de',
    cancel_url: 'https://app.sbpay.me/cancel/symphdev/custom/order/663/db6fcbd5e75e680148530448d1e5462d499b127bd0aa6bded733670da4eb30de',
    timestamp: '2025-03-04T05:08:20+00:00',
    algo: 'sha256',
    signature: '580479c08147ecfe2451ad55b7ad2b18c19ca1e0a092e0c93b5fd78693c5922e'
  }
}

And this is the Stripe session response/result:


{
  session: {
    id: 'cs_test_a1q1oOgZVJTddIjAAZshp6NZBlF1XzmNkPCGzGapAh2QcONfz0QqCf7cGa',
    object: 'checkout.session',
    adaptive_pricing: { enabled: false },
    after_expiration: null,
    allow_promotion_codes: null,
    amount_subtotal: 30000,
    amount_total: 30000,
    automatic_tax: { enabled: false, liability: null, status: null },
    billing_address_collection: null,
    cancel_url: 'https://app.sbpay.me/cancel/symphdev/custom/order/663/db6fcbd5e75e680148530448d1e5462d499b127bd0aa6bded733670da4eb30de',
    client_reference_id: '663',
    client_secret: null,
    collected_information: { shipping_details: null },
    consent: null,
    consent_collection: null,
    created: 1741064906,
    currency: 'sgd',
    currency_conversion: null,
    custom_fields: [],
    custom_text: {
      after_submit: null,
      shipping_address: null,
      submit: null,
      terms_of_service_acceptance: null
    },
    customer: null,
    customer_creation: 'if_required',
    customer_details: {
      address: null,
      email: 'jm.kuizon@symph.co',
      name: null,
      phone: null,
      tax_exempt: 'none',
      tax_ids: null
    },
    customer_email: 'jm.kuizon@symph.co',
    discounts: [],
    expires_at: 1741151306,
    invoice: null,
    invoice_creation: { enabled: true, invoice_data: [Object] },
    livemode: false,
    locale: null,
    metadata: {
      autoMakeInvoice: 'true',
      customer_id: '286',
      order_id: '663',
      timestamp: '2025-03-04T05:08:20+00:00'
    },
    mode: 'payment',
    payment_intent: null,
    payment_link: null,
    payment_method_collection: 'if_required',
    payment_method_configuration_details: null,
    payment_method_options: { card: [Object] },
    payment_method_types: [ 'card' ],
    payment_status: 'unpaid',
    phone_number_collection: { enabled: false },
    recovered_from: null,
    saved_payment_method_options: {
      allow_redisplay_filters: [Array],
      payment_method_remove: null,
      payment_method_save: null
    },
    setup_intent: null,
    shipping_address_collection: null,
    shipping_cost: null,
    shipping_options: [],
    status: 'open',
    submit_type: null,
    subscription: null,
    success_url: 'http://localhost:3333/api/v1/payments/confirm-payment/{CHECKOUT_SESSION_ID}?data=%7B%22order_id%22%3A%22663%22%2C%22amount%22%3A%22300%22%2C%22currency%22%3A%22SGD%22%2C%22customer_id%22%3A%22286%22%2C%22save_payment_method%22%3A%220%22%2C%22return_url%22%3A%22https%3A%2F%2Fapp.sbpay.me%2Freturn%2Fsymphdev%2Fcustom%2Forder%2F663%2Fdb6fcbd5e75e680148530448d1e5462d499b127bd0aa6bded733670da4eb30de%22%2C%22cancel_url%22%3A%22https%3A%2F%2Fapp.sbpay.me%2Fcancel%2Fsymphdev%2Fcustom%2Forder%2F663%2Fdb6fcbd5e75e680148530448d1e5462d499b127bd0aa6bded733670da4eb30de%22%2C%22timestamp%22%3A%222025-03-04T05%3A08%3A20%2B00%3A00%22%2C%22algo%22%3A%22sha256%22%2C%22signature%22%3A%22580479c08147ecfe2451ad55b7ad2b18c19ca1e0a092e0c93b5fd78693c5922e%22%7D',
    total_details: { amount_discount: 0, amount_shipping: 0, amount_tax: 0 },
    ui_mode: 'hosted',
    url: 'https://checkout.stripe.com/c/pay/cs_test_a1q1oOgZVJTddIjAAZshp6NZBlF1XzmNkPCGzGapAh2QcONfz0QqCf7cGa#fidkdWxOYHwnPyd1blpxYHZxWjA0VHRyUjZAa2pSYFAwZlU2dkdAT2Yxf2ZMR2lSUzZ8ckx9clR3UGRVXHJpYlczdWBUR31cTkd3XU1ENkkyVmdVdVVqRmxOQ2lddkJ0Z2x%2FPVZdVmRqTW82NTVOcUFpa1U1YScpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl'
  }
}

JM Kuizon wrote:

Here is the Postman request we did to approve the order:

POST https://app.sbpay.me/api/order/663/approve

Request Body:


{
  "algo": "sha256",
  "id": 663,
  "paymentMethod": "custom",
  "transactionId": "cs_test_a1q1oOgZVJTddIjAAZshp6NZBlF1XzmNkPCGzGapAh2QcONfz0QqCf7cGa",
  "reason": "Confirm Payment",
  "zeroAmount": true,
   "currency": "SGD"
}

Response result:


{"message":"Bad Request","data":[]}

We also added timestamp in the request body with the same response.

Transaction comes from the result of transaction in Stripe.

Raven Duran wrote:

Hi, we are experiencing this same issue as well.
Both Approve Order and Cancel Order API does not work or give a vague 400 Bad Request Error.

{
    "message": "Bad Request",
    "data": []
}

We followed the documentation. And we can even confirm that the following works:
GET https://app.sbpay.me/api/order/663
GET https://app.sbpay.me/api/payment-system/detailed?language=string HTTP/1.1

Which means we have successful connection to the API, and we have correct credentials. Just that Approve and Cancel Order does not properly work or is giving bad request error without reason.

Dmytro Bondarev wrote:

Hi, it must be current timestamp.
format is ISO 8601

JM Kuizon wrote:

Dmytro Bondarev wrote in #note-3:

Hi, it must be current timestamp.
format is ISO 8601

Hi,

I have updated the request body to:


{
  "timestamp": "2025-03-04T08:22:47+00:00",  // Current timestamp in ISO 8601 format
  "algo": "sha256",
  "id": 666,
  "paymentMethod": "custom",
  "transactionId": "cs_test_a1q1oOgZVJTddIjAAZshp6NZBlF1XzmNkPCGzGapAh2QcONfz0QqCf7cGa",
  "reason": "Confirm Payment",
  "zeroAmount": true
}

But I have the same error.

JM Kuizon wrote:

JM Kuizon wrote in #note-4:

Dmytro Bondarev wrote in #note-3:

Hi, it must be current timestamp.
format is ISO 8601

Hi,

I have updated the request body to:

[…]

But I have the same error.

Here is the screenshot of the Postman call with the error message: https://drive.google.com/file/d/1vvGVyIkm23OyBnokWBmT0ts2EZWJchH6/view?usp=sharing

And this is the actual error message:


{"message":"Validation error","data":{"errors":[{"path":"timestamp","error":"Invalid timestamp"}]}}

Dmytro Bondarev wrote:

Please make sure that you use exactly current timestamp.
If you still have the issue, please provide your company login (merchant)

JM Kuizon wrote:

Dmytro Bondarev wrote in #note-6:

Please make sure that you use exactly current timestamp.
If you still have the issue, please provide your company login (merchant)

Yes. I am using the current timestamp.

For the merchant ID it is: symphdev.

Thank you.

Dmytro Bondarev wrote:

The format is correct. But if difference will be more than 10 seconds it will not be accepted and you will receive this error.

JM Kuizon wrote:

Dmytro Bondarev wrote in #note-8:

The format is correct. But if difference will be more than 10 seconds it will not be accepted and you will receive this error.

Hi,

We are just simply passing the data that we got from the Payment form URL via SBPay custom payment.

This is the sample data that we got:


{
    order_id: '672',
    amount: '300',
    currency: 'SGD',
    customer_id: '286',
    save_payment_method: '0',
    return_url: 'https://app.sbpay.me/return/symphdev/custom/order/672/47c3c859e148cd9859054f4284c177e8e42765eba4bdff9f40a0711a81a5af5f',
    cancel_url: 'https://app.sbpay.me/cancel/symphdev/custom/order/672/47c3c859e148cd9859054f4284c177e8e42765eba4bdff9f40a0711a81a5af5f',
    timestamp: '2025-03-04T09:35:38+00:00',
    algo: 'sha256',
    signature: '811bc4f274a30edb3e1d63df671521a01574b76cc2536f3cd5ab0927aff129d8'
  }

Dmytro Bondarev wrote:

Ok, instead of passing timestamp from what you received from SBPay, please pass Current date and time.

JM Kuizon wrote:

Dmytro Bondarev wrote in #note-10:

Ok, instead of passing timestamp from what you received from SBPay, please pass Current date and time.

We are still getting the same error:


 async confirmPayment(sessionId: string, body: CreatePaymentDto) {
    try {
      const { signature, algo, order_id } = body;

      const response = await makeSimplyBookPayApiRequest(
        {
          'X-Signature': signature,
        },
        `/api/order/${order_id}/approve`,
        ApiMethods.POST,
        {
          timestamp: new Date().toISOString(),
          algo,
          id: order_id,
          paymentMethod: 'card',
          transactionId: sessionId,
          reason: 'Confirm Payment',
          zeroAmount: true,
        },
      );
      console.log(response);

      // return `${env.FRONTEND_URL}`;
    } catch (error) {
      throw new Error(`Failed to confirm payment: ${error.message}`);
    }
  }

Dmytro Bondarev wrote:

The only way to get the error is to pass invalid timestamp or invalid format.
When i call it for your merchant i get

X-Signature header is required

Because i don’t know secret and cannot pass it, but it is validated after timestamp.