EpitaCard API (2026-08-01)

Download OpenAPI specification:

License: LicenseRef-Private-Educational-Use

Test-mode EUR payment API for Epita marketplace teams.

EpitaCard is a Stripe-shaped payment provider. It supports one merchant per team, EUR integer minor units, synchronous payment outcomes, asynchronous signed events, and a same-origin merchant dashboard. Every resource is test mode only and carries livemode: false.

Constants

Property Value
API version 2026-08-01
Base URL / — Same-origin HTTPS proxy; local development uses port 9081.
Currency eur only
Amounts integer minor units (cents), maximum 9007199254740991
Mode test only; every resource carries livemode: false

Amounts are always integers. There is no decimal, no second currency, and no way to move this account to live mode.

Authentication

Your team owns one merchant and two keys.

Key Use
sk_test_… the API credential; send it on every /v1 request
pk_test_… a public identifier only — it never authorises a /v1 request

The secret key is accepted two ways. As a bearer token:

Authorization: Bearer sk_test_tNN_…

Or as HTTP Basic, with the secret key as the username and an empty password — which is what most clients produce from a user: credential pair:

Authorization: Basic <base64("sk_test_tNN_…:")>

A secret key is shown once, when it is issued and when it is rotated, and is stored only as a hash afterwards. Nobody can recover it for you; rotate to get a new one, which invalidates the old one immediately.

The merchant dashboard signs in with a browser session cookie. That session is not an API credential and cannot create or confirm a payment. If a session cookie rides along with an Authorization header the header wins, and a header and cookie belonging to different merchants are rejected with 401 credential_conflict.

Payment lifecycle

A payment intent starts at requires_payment_method.

Status Terminal Event emitted
requires_payment_method no —
processing no payment_intent.processing
succeeded yes payment_intent.succeeded
failed yes payment_intent.failed
From To Trigger
requires_payment_method processing confirmation
processing succeeded terminal_outcome_success
processing failed terminal_outcome_failure
processing failed processing_reclaim_timeout

Confirming an intent writes processing before it attempts any terminal status, then resolves to one. Whether a concurrent read sees that marker while the call is still running depends on Idempotency-Key: without the header the intent is readable at processing straight away; with it the intent keeps the state it had — or does not exist yet, when the create is what is being confirmed — until the call returns. Either way a client timeout never means the payment did not happen — re-read the intent. Confirming an intent that already left requires_payment_method returns 400 invalid_request.

There is no cancellation and no refund. A payment that must not stand is a business problem on your side, not an API call.

Test cards

Pass one of these tokens as payment_method. Any other card number is rejected with 400 invalid_request.

payment_method Result Payment intent status Error code HTTP
pm_card_4242424242424242 success succeeded — 201
pm_card_4000000000000002 decline failed card_declined 402
pm_card_4000000000009995 decline failed insufficient_funds 402
pm_card_4000000000000069 decline failed expired_card 402
pm_card_4000000000000127 decline failed incorrect_cvc 402
pm_card_4000000000000119 processing failure failed processing_error 402

Errors and retries

Code Type HTTP Retriable
invalid_request invalid_request_error 400 no — terminal
invalid_api_key authentication_error 401 no — terminal
credential_conflict authentication_error 401 no — terminal
card_declined card_error 402 no — terminal
insufficient_funds card_error 402 no — terminal
expired_card card_error 402 no — terminal
incorrect_cvc card_error 402 no — terminal
processing_error card_error 402 yes
resource_missing invalid_request_error 404 no — terminal
idempotency_error idempotency_error 409 no — terminal
order_amount_mismatch invalid_request_error 409 no — terminal
rate_limited rate_limit_error 429 yes
api_error api_error 500 yes
service_unavailable api_error 503 yes

Only processing_error, rate_limited, api_error and service_unavailable are worth retrying. Retrying a terminal code produces the same answer.

Retry with the same order_id. That is what stops a retry from charging your buyer twice.

Idempotency

Two independent protections.

1. Idempotency-Key header. Supported on:

  • POST /v1/payment_intents
  • POST /v1/payment_intents/{id}/confirm

A repeat of the same request with the same key replays the stored response and adds Idempotent-Replayed: true. Requests are matched on method, request_path, canonical_body, so the same key sent with a different body, or against a different PaymentIntent, returns 409 idempotency_error. A stored response is kept only for status 200, 201, 402, 409; status 400, 404, 500 does not consume the key, so a retry gets a fresh attempt. An absent body and {} are the same request.

GET requests ignore the header. These routes reject it with 400:

  • POST /v1/webhook_endpoints
  • PATCH /v1/webhook_endpoints/{id}
  • POST /v1/api_keys/rotate

2. (merchant, order_id) uniqueness. This one needs no header, which makes it the protection that covers a retry after a network timeout. Re-creating an intent for an order_id you already used returns the existing intent with 200 when the amount matches, and 409 order_amount_mismatch when it does not.

Pagination

payment_intents, events, webhook_endpoints, webhook_deliveries are ordered by created DESC then id DESC. Pass the last ID you received as starting_after to get the next page; the server selects rows where created < cursor.created OR (created = cursor.created AND id < cursor.id). Every list response carries has_more and next_starting_after.

Webhooks

Register an HTTPS endpoint you control with POST /v1/webhook_endpoints and keep the whsec_… signing secret it returns. There are exactly 3 event types:

  • payment_intent.succeeded
  • payment_intent.failed
  • payment_intent.processing

Delivery is at least once with bounded retries, so de-duplicate on event.id. Delivery never changes or delays the synchronous API response you already got.

Every delivery carries an EpitaCard-Signature header:

EpitaCard-Signature: t=1786900201,v1=0000000000000000000000000000000000000000000000000000000000000000

t=<unix>,v1=<hex hmac_sha256(secret, timestamp + "." + raw_body)>. Reject timestamps outside a five-minute window and compare decoded MAC bytes in constant time.

Read the raw body before decoding it — re-serialised JSON does not produce the same MAC:

func verifyEpitaCardSignature(secret, header string, body []byte, now time.Time) error {
    var timestampText, signatureHex string
    for _, part := range strings.Split(header, ",") {
        key, value, ok := strings.Cut(strings.TrimSpace(part), "=")
        if !ok {
            continue
        }
        switch key {
        case "t":
            timestampText = value
        case "v1":
            signatureHex = value
        }
    }
    timestamp, err := strconv.ParseInt(timestampText, 10, 64)
    if err != nil {
        return fmt.Errorf("invalid signature timestamp: %w", err)
    }
    delta := now.Unix() - timestamp
    if delta < -300 || delta > 300 {
        return errors.New("signature timestamp outside five-minute window")
    }
    received, err := hex.DecodeString(signatureHex)
    if err != nil {
        return fmt.Errorf("invalid v1 signature: %w", err)
    }
    mac := hmac.New(sha256.New, []byte(secret))
    _, _ = io.WriteString(mac, timestampText+".")
    _, _ = mac.Write(body)
    if !hmac.Equal(received, mac.Sum(nil)) {
        return errors.New("signature mismatch")
    }
    return nil
}

hmac.Equal is the constant-time comparison; == on the hex strings leaks timing. Verify before unmarshalling and before any side effect.

PaymentIntents

Create, confirm, retrieve, and search payment attempts.

Create a payment intent

Creates an intent in EUR cents. Supplying payment_method immediately confirms it: confirmation writes processing and its event first, then one terminal result. Omitting the field returns requires_payment_method. Secret-key authentication is mandatory. Header idempotency is evaluated before (merchant, order_id) uniqueness. Confirmation reserves aggregate merchant headroom before processing and rejects a safe-integer-ceiling breach with 400 invalid_request.

Sending Idempotency-Key changes when the intent becomes readable. Without the header the processing intent is durable as soon as it is written, so a concurrent GET made while the call is still running already returns it at processing — which is why a client that times out still finds its payment. With the header nothing is durable until the call returns: a concurrent GET returns 404 until then, and the intent appears only once it does. What it appears as depends on the status. On 200, 201, 402 or 409 the intent is in its final state and the key holds the response it will replay. On 400, 404 or 500 no response is stored and the key is released for a fresh attempt, and the intent can be left readable at processing with no charge — resolved later like any other unfinished processing intent. Either way, once the call has returned the intent is readable and a timeout never means the payment did not happen.

Authorizations:
SecretKeyBearerSecretKeyBasic
header Parameters
Idempotency-Key
string [ 1 .. 255 ] characters
Example: billing-order-00042

De-duplicates this payment mutation for 24 hours. The fingerprint covers the method, the concrete request path and the canonical JSON body, so a key reused against a different PaymentIntent returns 409 instead of replaying the first one. A matching fingerprint replays the stored response.

Request Body schema: application/json
required
amount
required
integer <int64> (Amount) [ 1 .. 9007199254740991 ]

EUR integer minor units (cents), capped at the JSON safe-integer maximum so RFC 8785 idempotency fingerprints preserve exact amounts.

order_id
required
string [ 1 .. 255 ] characters
payment_method
string^pm_card_[0-9]{16}$
description
string or null <= 500 characters
receipt_email
string or null <email> <= 320 characters
buyer_name
string or null <= 255 characters
object (Metadata) <= 50 properties

Responses

Request samples

Content type
application/json
Example
{
  • "amount": 1999,
  • "order_id": "order_2026_00042",
  • "payment_method": "pm_card_4242424242424242",
  • "description": "Marché Nord order 42",
  • "receipt_email": "buyer@example.test",
  • "buyer_name": "Alice Martin",
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "id": "pi_EXAMPLE_SUCCEEDED",
  • "object": "payment_intent",
  • "livemode": false,
  • "amount": 1999,
  • "currency": "eur",
  • "status": "succeeded",
  • "order_id": "order_2026_00042",
  • "created": 1786900000,
  • "description": "Marché Nord order 42",
  • "receipt_email": "buyer@example.test",
  • "buyer_name": "Alice Martin",
  • "statement_descriptor": "EPITACARD* MARCHE NORD",
  • "metadata": {
    },
  • "latest_charge": {
    },
  • "last_payment_error": null
}

List payment intents

Returns owner-scoped intents ordered by (created DESC, id DESC) with a strict tuple cursor. Per-status counts honor q but ignore status, limit, and cursor so dashboard tabs remain comparable.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession
query Parameters
status
string (PaymentIntentStatus)
Enum: "requires_payment_method" "processing" "succeeded" "failed"
Example: status=failed

Restrict results to one lifecycle status.

q
string [ 1 .. 255 ] characters
Example: q=Alice

Matches ID, order ID, buyer name, or amount. Amount accepts integer cents or fixed two-decimal EUR.

limit
integer [ 1 .. 100 ]
Default: 20
Example: limit=20

Maximum page size.

starting_after
string non-empty
Example: starting_after=pi_EXAMPLE_SUCCEEDED

Last resource ID from the preceding page. The server resolves its (created, id) tuple and applies the strict descending lexicographic comparison defined by x-epitacard-pagination.

Responses

Response samples

Content type
application/json
{
  • "object": "list",
  • "livemode": false,
  • "data": [
    ],
  • "has_more": false,
  • "next_starting_after": null,
  • "counts": {
    }
}

Retrieve a payment intent

Returns one owner-scoped PaymentIntent.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession
path Parameters
id
required
string^pi_[A-Za-z0-9_]+$
Example: pi_EXAMPLE_SUCCEEDED

Owner-scoped PaymentIntent ID.

Responses

Response samples

Content type
application/json
{
  • "id": "pi_EXAMPLE_SUCCEEDED",
  • "object": "payment_intent",
  • "livemode": false,
  • "amount": 1999,
  • "currency": "eur",
  • "status": "succeeded",
  • "order_id": "order_2026_00042",
  • "created": 1786900000,
  • "description": "Marché Nord order 42",
  • "receipt_email": "buyer@example.test",
  • "buyer_name": "Alice Martin",
  • "statement_descriptor": "EPITACARD* MARCHE NORD",
  • "metadata": {
    },
  • "latest_charge": {
    },
  • "last_payment_error": null
}

Confirm a payment intent

Confirms a requires_payment_method intent. It first writes processing and that event, then a terminal result. Confirming processing, succeeded, or failed returns 400 invalid_request. The body may omit payment_method only when one is already attached. An omitted body and {} share the same idempotency fingerprint. Secret-key authentication is mandatory. Aggregate merchant headroom is reserved before the processing marker.

As on create, Idempotency-Key changes when the new state becomes readable. Without the header a concurrent GET observes processing while the call is still running. With the header the intent keeps its previous status for concurrent readers until the call returns. It then changes straight to its final state together with the response the key will replay on 200, 201, 402 or 409. On 400, 404 or 500 nothing is stored, the key is released for a fresh attempt, and the intent can be left readable at processing with no charge — resolved later like any other unfinished processing intent.

Authorizations:
SecretKeyBearerSecretKeyBasic
path Parameters
id
required
string^pi_[A-Za-z0-9_]+$
Example: pi_EXAMPLE_SUCCEEDED

Owner-scoped PaymentIntent ID.

header Parameters
Idempotency-Key
string [ 1 .. 255 ] characters
Example: billing-order-00042

De-duplicates this payment mutation for 24 hours. The fingerprint covers the method, the concrete request path and the canonical JSON body, so a key reused against a different PaymentIntent returns 409 instead of replaying the first one. A matching fingerprint replays the stored response.

Request Body schema: application/json
optional
payment_method
string^pm_card_[0-9]{16}$

Responses

Request samples

Content type
application/json
Example
{
  • "payment_method": "pm_card_4242424242424242"
}

Response samples

Content type
application/json
Example
{
  • "id": "pi_EXAMPLE_SUCCEEDED",
  • "object": "payment_intent",
  • "livemode": false,
  • "amount": 1999,
  • "currency": "eur",
  • "status": "succeeded",
  • "order_id": "order_2026_00042",
  • "created": 1786900000,
  • "description": "Marché Nord order 42",
  • "receipt_email": "buyer@example.test",
  • "buyer_name": "Alice Martin",
  • "statement_descriptor": "EPITACARD* MARCHE NORD",
  • "metadata": {
    },
  • "latest_charge": {
    },
  • "last_payment_error": null
}

Balance

Read total settled revenue.

Retrieve the merchant balance

Returns the merchant's settled EUR cents: the total of every succeeded charge, summed in exact arbitrary precision. There is one figure and no withdrawal route, so nothing is ever held back or in flight. An invariant breach above the JSON safe-integer ceiling returns 500 api_error; values are never capped or truncated.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession

Responses

Response samples

Content type
application/json
{
  • "object": "balance",
  • "livemode": false,
  • "settled": {
    }
}

Events

Read immutable merchant event history.

Receive a signed EpitaCard event Webhook

EpitaCard sends this request at least once to each enabled, subscribed team endpoint. Verify the signature against the raw request body before decoding JSON, enforce the five-minute replay window, compare MAC bytes in constant time, and de-duplicate by event ID. Delivery outcome never changes the originating synchronous API response.

header Parameters
EpitaCard-Signature
required
string^t=[0-9]+,v1=[a-f0-9]{64}$
Example: t=1786900201,v1=0000000000000000000000000000000000000000000000000000000000000000

t=<unix>,v1=<hex hmac_sha256(secret, timestamp + "." + raw_body)>. Reject timestamps outside a five-minute window and compare decoded MAC bytes in constant time.

Request Body schema: application/json
required
id
required
string^evt_[A-Za-z0-9_]+$
object
required
string
Value: "event"
livemode
required
boolean (Livemode)
type
required
string (EventType)
Enum: "payment_intent.succeeded" "payment_intent.failed" "payment_intent.processing"
created
required
integer <int64> (UnixTimestamp) >= 0
required
object (EventData)
required
object (EventRequest)

Responses

Request samples

Content type
application/json
{
  • "id": "evt_EXAMPLE_SUCCEEDED",
  • "object": "event",
  • "livemode": false,
  • "type": "payment_intent.succeeded",
  • "created": 1786900201,
  • "data": {
    },
  • "request": {
    }
}

Response samples

Content type
application/json
{
  • "received": true
}

List events

Returns immutable owner-scoped events ordered by (created DESC, id DESC) with a strict tuple cursor.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession
query Parameters
limit
integer [ 1 .. 100 ]
Default: 20
Example: limit=20

Maximum page size.

starting_after
string non-empty
Example: starting_after=pi_EXAMPLE_SUCCEEDED

Last resource ID from the preceding page. The server resolves its (created, id) tuple and applies the strict descending lexicographic comparison defined by x-epitacard-pagination.

Responses

Response samples

Content type
application/json
{
  • "object": "list",
  • "livemode": false,
  • "data": [
    ],
  • "has_more": false,
  • "next_starting_after": null
}

Retrieve an event

Returns an EventDetail read projection that adds the latest delivery to the immutable stored Event. The projection is not the signed webhook body.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession
path Parameters
id
required
string^evt_[A-Za-z0-9_]+$
Example: evt_EXAMPLE_SUCCEEDED

Owner-scoped Event ID.

Responses

Response samples

Content type
application/json
{
  • "id": "evt_EXAMPLE_SUCCEEDED",
  • "object": "event",
  • "livemode": false,
  • "type": "payment_intent.succeeded",
  • "created": 1786900201,
  • "data": {
    },
  • "request": {
    },
  • "latest_delivery": {
    }
}

WebhookEndpoints

Register and inspect signed event destinations.

Register a webhook endpoint

Registers an owner-scoped HTTPS destination and returns its recoverable signing secret. In deployed mode URLs must use HTTPS, resolve only to public addresses, and pass the no-redirect, validated-IP dialing policy. Idempotency-Key is rejected with 400. Secret-key authentication is mandatory.

Authorizations:
SecretKeyBearerSecretKeyBasic
header Parameters
Idempotency-Key
string [ 1 .. 255 ] characters
Example: unsupported-on-this-route

Supplying this header to this mutation returns 400 invalid_request.

Request Body schema: application/json
required
url
required
string <uri> <= 2048 characters
enabled
boolean
Default: true
subscribed_events
required
Array of strings (EventType) non-empty unique
Items Enum: "payment_intent.succeeded" "payment_intent.failed" "payment_intent.processing"

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "id": "we_EXAMPLE_TEAM07",
  • "object": "webhook_endpoint",
  • "livemode": false,
  • "enabled": true,
  • "subscribed_events": [
    ],
  • "secret": "whsec_EXAMPLE_NOT_A_REAL_SECRET",
  • "created": 1786800000,
  • "updated": 1786800000
}

List webhook endpoints

Returns owner-scoped endpoints, including secrets, ordered by (created DESC, id DESC) with a strict tuple cursor.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession
query Parameters
limit
integer [ 1 .. 100 ]
Default: 20
Example: limit=20

Maximum page size.

starting_after
string non-empty
Example: starting_after=pi_EXAMPLE_SUCCEEDED

Last resource ID from the preceding page. The server resolves its (created, id) tuple and applies the strict descending lexicographic comparison defined by x-epitacard-pagination.

Responses

Response samples

Content type
application/json
{
  • "object": "list",
  • "livemode": false,
  • "data": [
    ],
  • "has_more": false,
  • "next_starting_after": null
}

Retrieve a webhook endpoint

Returns one owner-scoped endpoint and its signing secret.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession
path Parameters
id
required
string^we_[A-Za-z0-9_]+$
Example: we_EXAMPLE_TEAM07

Owner-scoped WebhookEndpoint ID.

Responses

Response samples

Content type
application/json
{
  • "id": "we_EXAMPLE_TEAM07",
  • "object": "webhook_endpoint",
  • "livemode": false,
  • "enabled": true,
  • "subscribed_events": [
    ],
  • "secret": "whsec_EXAMPLE_NOT_A_REAL_SECRET",
  • "created": 1786800000,
  • "updated": 1786800000
}

Update or disable a webhook endpoint

Updates URL, enabled state, or event subscriptions. Use enabled=false instead of deleting an endpoint. Changed URLs are revalidated under the same HTTPS, public-address, no-redirect, validated-IP dialing policy. Idempotency-Key is rejected with 400. Session calls require CSRF protection.

Authorizations:
SecretKeyBearerSecretKeyBasic(DashboardSessionCsrfToken)
path Parameters
id
required
string^we_[A-Za-z0-9_]+$
Example: we_EXAMPLE_TEAM07

Owner-scoped WebhookEndpoint ID.

header Parameters
X-CSRF-Token
string >= 16 characters
Example: EXAMPLE_CSRF_TOKEN

Required only when authentication uses the dashboard cookie.

Idempotency-Key
string [ 1 .. 255 ] characters
Example: unsupported-on-this-route

Supplying this header to this mutation returns 400 invalid_request.

Request Body schema: application/json
required
non-empty
url
string <uri> <= 2048 characters
enabled
boolean
subscribed_events
Array of strings (EventType) non-empty unique
Items Enum: "payment_intent.succeeded" "payment_intent.failed" "payment_intent.processing"

Responses

Request samples

Content type
application/json
Example
{
  • "enabled": false
}

Response samples

Content type
application/json
{
  • "id": "we_EXAMPLE_TEAM07",
  • "object": "webhook_endpoint",
  • "livemode": false,
  • "enabled": false,
  • "subscribed_events": [
    ],
  • "secret": "whsec_EXAMPLE_NOT_A_REAL_SECRET",
  • "created": 1786800000,
  • "updated": 1786900300
}

List deliveries for a webhook endpoint

Returns owner-scoped Event, Object, Result, Attempts, and Sent data ordered by (created DESC, id DESC) with a strict tuple cursor.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession
path Parameters
id
required
string^we_[A-Za-z0-9_]+$
Example: we_EXAMPLE_TEAM07

Owner-scoped WebhookEndpoint ID.

query Parameters
limit
integer [ 1 .. 100 ]
Default: 20
Example: limit=20

Maximum page size.

starting_after
string non-empty
Example: starting_after=pi_EXAMPLE_SUCCEEDED

Last resource ID from the preceding page. The server resolves its (created, id) tuple and applies the strict descending lexicographic comparison defined by x-epitacard-pagination.

Responses

Response samples

Content type
application/json
{
  • "object": "list",
  • "livemode": false,
  • "data": [
    ],
  • "has_more": false,
  • "next_starting_after": null
}

APIKeys

Inspect key metadata and rotate the active secret key.

Retrieve API key metadata

Returns the publishable key and active secret prefix, never the secret.

Authorizations:
SecretKeyBearerSecretKeyBasicDashboardSession

Responses

Response samples

Content type
application/json
{
  • "object": "api_keys",
  • "livemode": false,
  • "publishable_key": "pk_test_t07_2Bn8xQ",
  • "secret_key_prefix": "sk_test_t07_EXAMPL"
}

Rotate the active secret key

Returns a replacement secret exactly once and invalidates the old key. Session calls require CSRF protection. Idempotency-Key returns 400, because replaying a stored secret would violate one-time disclosure.

Authorizations:
SecretKeyBearerSecretKeyBasic(DashboardSessionCsrfToken)
header Parameters
X-CSRF-Token
string >= 16 characters
Example: EXAMPLE_CSRF_TOKEN

Required only when authentication uses the dashboard cookie.

Idempotency-Key
string [ 1 .. 255 ] characters
Example: unsupported-on-this-route

Supplying this header to this mutation returns 400 invalid_request.

Request Body schema: application/json
optional
<= 0 properties
object (EmptyObject) <= 0 properties

Responses

Request samples

Content type
application/json
{ }

Response samples

Content type
application/json
{
  • "object": "api_key",
  • "livemode": false,
  • "publishable_key": "pk_test_t07_2Bn8xQ",
  • "secret_key": "sk_test_t07_ABCDEFGHIJKLMNOPQRSTUVWXYZ012345",
  • "secret_key_prefix": "sk_test_t07_EXAMPL",
  • "created": 1786900400
}

Dashboard

Authenticate merchants and read the owner-scoped request log.

Create a dashboard session

Authenticates one merchant account and sets two cookies: the epitacard_session credential and its readable epitacard_csrf companion. The response body supplies the same CSRF token used by same-origin dashboard mutations. A separate limiter keyed by client IP plus trimmed, Unicode-lowercased email returns 429 with Retry-After.

Request Body schema: application/json
required
email
required
string <email> <= 320 characters
password
required
string [ 1 .. 1024 ] characters

Responses

Request samples

Content type
application/json
{
  • "email": "team07@epita.fr",
  • "password": "EXAMPLE_NOT_A_REAL_PASSWORD"
}

Response samples

Content type
application/json
{
  • "object": "dashboard_session",
  • "livemode": false,
  • "csrf_token": "EXAMPLE_CSRF_TOKEN",
  • "expires_at": 1786986800
}

Read the merchant request log

Returns the owning merchant's newest 200 request-log records.

Authorizations:
DashboardSession

Responses

Response samples

Content type
application/json
{
  • "object": "list",
  • "livemode": false,
  • "data": [
    ],
  • "limit": 200
}

Read per-day payment volume

Aggregates the owning merchant's PaymentIntents into the caller's day buckets in one request, for the dashboard overview chart. Day i counts intents created at or after day_starts[i] and before day_starts[i+1]; the last day is open-ended. Intents created before the first boundary are not counted. Days without intents are returned with zero totals.

Authorizations:
DashboardSession
query Parameters
day_starts
required
string^[0-9]+(,[0-9]+){0,30}$
Example: day_starts=1786579200,1786665600,1786752000

Comma-separated, strictly increasing Unix timestamps in seconds, usually the viewer's local midnights. At most 31 values, none more than a day ahead, the first no more than 32 days ago.

Responses

Response samples

Content type
application/json
{
  • "object": "payment_volume",
  • "livemode": false,
  • "days": [
    ]
}

PublicVAT

Public destination-country VAT rates.

Retrieve destination-country VAT rates

Public, unauthenticated lookup. Rates are decimal fractions, and reduced-rate keys are lowercase shop category names. The static table currently supports France. This free-tier endpoint can return a temporary failure; its responses must not be cached.

query Parameters
country
required
string^[A-Z]{2}$
Example: country=FR

Uppercase ISO 3166-1 alpha-2 country code.

Responses

Response samples

Content type
application/json
{
  • "country": "FR",
  • "standard_rate": 0.2,
  • "reduced_rates": {
    },
  • "as_of": "2026-01-01"
}