Appearance
Schemas
Response Envelope
TransactCore uses two response formats depending on the endpoint:
Success (with data wrapper)
Used by GET /payment-intents/{id}:
json
{
"data": {
"payment_intent_id": "pi_3abc123",
"amount": 3420,
"currency": "usd",
"status": "succeeded"
}
}Success (flat)
Used by POST /payment-intents and GET /config/stripe:
json
{
"client_secret": "pi_3abc123_secret_xyz789",
"payment_intent_id": "pi_3abc123",
"publishable_key": "pk_live_xxxxx",
"amount": 3420,
"currency": "usd"
}Error
json
{
"error": "Error message describing what went wrong",
"message": "Additional details (optional)"
}error is not always a string
When an endpoint is relaying an error Stripe returned, error is an object (type, code, decline_code, param, message, request_id) rather than a string — this is how Create Payment Intent reports card declines and Stripe API errors. Refund Payment Intent keeps error a string and puts the same structure in a separate stripe_error key. Check the shape before treating error as text.
Validation Error
json
{
"message": "The amount field must be at least 50.",
"errors": {
"amount": ["The amount field must be at least 50."]
}
}Common Error Codes
| HTTP Status | Error | Description |
|---|---|---|
400 | Payment account cannot accept payments | Connected account has incomplete onboarding or is restricted |
401 | Unauthenticated | Missing or invalid Bearer token |
403 | Forbidden | Token does not have the required scope |
404 | Payment intent not found | No payment intent exists with the given ID |
404 | No payment account configured | Organization has no connected Stripe account |
404 | No completed transaction found for this payment intent | Intent carries no succeeded charge to refund |
400 | Payment intent cannot be canceled | Local state rules cancellation out (already succeeded or canceled) |
400 | Payment intent cannot be captured | Not a manual capture intent awaiting capture |
400 | Transaction cannot be refunded | Charge did not succeed, or is already fully refunded |
400 | Refund amount exceeds refundable amount | Requested amount is above the charge's remaining balance |
422 | Validation error | Request body failed validation (see errors object) |
422 | Unable to cancel payment intent | Local state allowed the attempt but the gateway refused it |
422 | Refund could not be processed | Deterministic Stripe error (4xx other than 429) — retrying will not help |
429 | Too many requests | Rate limit exceeded (100/min per IP on the ecommerce endpoints) |
4xx/502 | Stripe API error object | Create Payment Intent mirrors Stripe's own HTTP status, falling back to 502 |
500 | Failed to create/capture/refund … | Non-Stripe failure, or a retryable Stripe 429/5xx on refund |
Currency
All amounts are in the smallest currency unit (cents for USD).
| Amount | Meaning |
|---|---|
50 | $0.50 (minimum) |
3420 | $34.20 |
100000 | $1,000.00 |
The currency field accepts ISO 4217 three-letter codes. Default: usd.
Rate Limit Headers
All responses include rate limit information:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Remaining requests in current window |
Retry-After | Seconds until reset (only on 429 responses) |
All ecommerce endpoints: 100 requests per minute per IP address.
Hashkeys
TransactCore uses hashkeys as external identifiers for resources. Hashkeys are prefixed strings that encode internal IDs:
| Resource | Prefix | Example |
|---|---|---|
| Connected Account | cct_ | cct_00000k1L2m3N4o5 |
| Organization | org_ | org_00000k1L2m3N4o5 |
Payment intents use Stripe's native IDs (e.g., pi_3abc123) rather than hashkeys.
Changelog
| Date | Change |
|---|---|
| 2026-09-12 | Noted that error is an object when relaying a Stripe error, and expanded the Common Error Codes table to cover the capture and refund paths. |
| 2026-03-19 | Initial publication. |