← Back to the tool

Unix Timestamps in REST APIs

Updated: May 2026

There is no universal standard for how REST APIs represent time. Some use Unix seconds, others use ISO 8601 strings, and some use milliseconds. Knowing which convention a specific API follows — and how to translate between them — saves hours of debugging when integrating third-party services.

Decode any timestamp →

Free · No upload · Instant

Seconds vs ISO 8601 — the two camps

Most major APIs fall into one of two camps:

  • Unix seconds integers — Stripe, Twilio, SendGrid, most financial APIs. Compact, sortable, unambiguous, easy to compare and do arithmetic with. The unit is always seconds.
  • ISO 8601 strings — GitHub, Google, AWS, Salesforce, most modern REST APIs. Human-readable, self-describing, includes timezone offset. Format: 2025-01-01T00:00:00Z.

When consuming an API, always check the documentation for the unit. When designing your own API, pick one convention and document it clearly in every field description. Mixed conventions in the same API are a common source of client-side bugs.

Stripe — pure Unix seconds

Stripe is the canonical example of the Unix-seconds convention. Every date field in the Stripe API is an integer count of seconds since the Unix epoch, with no exceptions.

// Stripe charge object (simplified)
{
  "id": "ch_3QxyzABC123",
  "created": 1735689600,          // Unix seconds
  "amount": 4999,
  "currency": "usd",
  "customer": "cus_ABC123"
}

// Convert in JavaScript
const created = new Date(charge.created * 1000).toISOString();
// → "2025-01-01T00:00:00.000Z"

// Filter by date in a Stripe list
const charges = await stripe.charges.list({
  created: {
    gte: 1735689600,              // Jan 1, 2025 00:00:00 UTC
    lt:  1767225600               // Jan 1, 2026 00:00:00 UTC
  }
});

Rate-limit headers — often Unix timestamps

Many APIs communicate rate limit reset times as Unix timestamps in response headers. The standard X-RateLimit-Reset header (GitHub, Twitter, and others) contains a Unix timestamp in seconds indicating when the rate limit window resets.

// Rate limit headers example
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1735693200     // Unix seconds

// Convert to human time in JavaScript
const resetTs = parseInt(response.headers['x-ratelimit-reset']);
const resetDate = new Date(resetTs * 1000);
const waitMs = resetDate - Date.now();
console.log(`Rate limited. Resets at ${resetDate.toISOString()}`);
console.log(`Wait ${Math.ceil(waitMs / 1000)} seconds`);

Cursor-based pagination with timestamps

Many APIs use Unix timestamps as pagination cursors. Instead of page numbers, you pass the timestamp of the last item received to get the next page. This is stable even when items are inserted concurrently.

// Slack conversations.history uses Unix timestamp cursors
// First page — most recent 100 messages
GET /api/conversations.history?channel=C123&limit=100

// Response contains:
{
  "messages": [...],
  "has_more": true,
  "response_metadata": {
    "next_cursor": "bmV4dF90czoxNzM1Njg5NjAw"  // base64
  }
}

// Some APIs use raw timestamp as cursor (e.g. oldest/latest)
GET /api/conversations.history?channel=C123&oldest=1735689600&latest=1735693200

// Twitter/X uses since_id and max_id for tweet IDs
// but older search APIs used Unix timestamps directly

Webhook timestamps and replay protection

Webhooks from Stripe, GitHub and other services include a timestamp in the signature header to prevent replay attacks. The receiving server should reject webhooks with a timestamp more than 5 minutes old.

// Stripe webhook signature header
Stripe-Signature: t=1735689600,v1=abc123...

// Extract and validate
function validateStripeWebhook(payload, header, secret) {
  const parts = header.split(',');
  const ts = parseInt(parts[0].split('=')[1]);
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - ts) > 300) {
    throw new Error('Webhook timestamp too old — possible replay attack');
  }
  // ... verify HMAC signature
}

When debugging webhook delivery issues, paste the timestamp from the header into the Flowfiles converter to verify it matches the expected delivery time and is within the 5-minute validation window.

API design recommendations

  • Choose one format and apply it everywhere. If you use Unix seconds for one endpoint, use it for all endpoints. Mixed conventions are the biggest source of client confusion.
  • Document the unit in the field name or description. Names like created_at are ambiguous. created_at_s or a schema annotation ("format": "unix-timestamp-seconds") removes all doubt.
  • Accept ISO 8601 on input. Many clients find it easier to send "2025-01-01T00:00:00Z" than to compute a Unix timestamp. Accept both and normalise internally.
  • Return both for important fields. Some APIs return both "created": 1735689600 and "created_iso": "2025-01-01T00:00:00Z" — convenient for debugging without increasing payload size significantly.
  • Use 64-bit integers. Future-proof your API by specifying int64 or bigint in your schema definitions, not int32.