RK
RefundKit

Error Handling

Error Handling

Every SDK method returns a { data, error } tuple instead of throwing exceptions. This design makes error handling explicit and predictable across your codebase.

The Response Pattern

Exactly one of data or error will be non-null in every response:

import RefundKit from '@refundkit/sdk';

const rk = new RefundKit({ apiKey: process.env.REFUNDKIT_API_KEY! });

const { data, error } = await rk.refunds.create({
  transactionId: 'ch_1N4HbSKz9cXRvFYr',
  amount: 2500,
  reason: 'customer_request',
});

if (error) {
  // Handle the error -- data is null
  console.error(error.message);
  return;
}

// Use the data -- error is null
console.log(data.id);

RefundKitError Object

When an error occurs, the error field contains a RefundKitError with the following properties:

| Property | Type | Description | |----------|------|-------------| | message | string | Human-readable error description | | code | string | Machine-readable error code for programmatic handling | | statusCode | number | HTTP status code from the API response |

if (error) {
  console.error('Message:', error.message);     // "Invalid API key"
  console.error('Code:', error.code);           // "invalid_api_key"
  console.error('Status:', error.statusCode);   // 401
}

Common Error Codes

| Code | Status | Description | |------|--------|-------------| | invalid_api_key | 401 | The API key is missing, malformed, or revoked | | not_found | 404 | The requested refund or transaction does not exist | | validation_error | 400 | The request body failed validation (missing or invalid fields) | | refund_already_processed | 409 | The refund has already been completed or cancelled | | policy_violation | 403 | The refund violates a configured policy rule | | processor_error | 502 | The payment processor returned an error | | timeout | 408 | The request exceeded the configured timeout | | rate_limit_exceeded | 429 | Too many requests; back off and retry |

Handling Specific Errors

Use the code property to handle errors programmatically:

const { data, error } = await rk.refunds.cancel('ref_xyz789');

if (error) {
  switch (error.code) {
    case 'not_found':
      console.error('Refund does not exist');
      break;
    case 'refund_already_processed':
      console.error('Cannot cancel a completed refund');
      break;
    case 'rate_limit_exceeded':
      console.error('Too many requests, retrying...');
      // implement retry logic
      break;
    default:
      console.error('Unexpected error:', error.message);
  }
}

Validation Errors

When the SDK validates input before sending a request (using Zod), it returns a validation_error code with a descriptive message indicating which field failed:

const { error } = await rk.refunds.create({
  transactionId: '',  // empty string
  amount: -100,       // negative amount
  reason: 'test',
});

if (error?.code === 'validation_error') {
  console.error(error.message);
  // "transactionId must be a non-empty string"
}

Network and Timeout Errors

If the API is unreachable or the request exceeds the configured timeout, the SDK wraps the underlying error:

const rk = new RefundKit({
  apiKey: process.env.REFUNDKIT_API_KEY!,
  timeout: 5000, // 5 seconds
});

const { error } = await rk.refunds.list();

if (error?.code === 'timeout') {
  console.error('Request timed out after 5 seconds');
}

Next Steps

  • TypeScript -- TypeScript types and inference for SDK responses.
  • Errors Reference -- Full list of error codes and HTTP status mappings.