# Payments

Clearing status, execution, and refunds.

## Stream finished payments

`GET /v1/payments/stream`

A Server-Sent Events stream of the merchant's payments as they finish, for a livestream overlay or a live view. The first event is `ready`, a `ping` follows every 15 seconds, and each finished payment is a `payment` event whose `data` is a `PaymentFeedEvent` and whose `id` is when it finished. Only an outcome is announced, once: `payment.completed` when the money arrived, `payment.failed` when it did not. To catch up after a disconnect send `since` (or the `Last-Event-ID` an `EventSource` sends): payments that finished after that time are replayed first, oldest first, and one may repeat at the seam, so drop a repeat by `id`. A merchant may hold 5 streams open at once; the sixth is a 429.

### Query parameters

- `since` `string`: ISO 8601 time. Replay payments that finished after it before going live.
- `key` `string`: An `ak_` alert key, for a browser source that cannot set a header. A secret key is refused here.

### Responses

#### `200`: An event stream. Each `payment` event's `data` is the JSON below.

Body (`text/event-stream`):

- `id` `string` _(required)_: `<payment intent id>:<status>`. Stable, so a repeat can be dropped.
- `type` `string` _(required)_
- `occurredAt` `string` _(required)_: When the payment finished. Send it back as `since` to resume.
- `data` `object` _(required)_
  - `paymentIntentId` `string` _(required)_
  - `status` `string` _(required)_
  - `amount` `object & unknown` _(required)_
  - `settlement` `object | null` _(required)_: What reached the merchant. `null` when nothing settled.
    - `amount` `object` _(required)_
      - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
      - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
      - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
      - `display` `string` _(required)_: Localized display text. Never parse this value.
    - `fee` `object & object | null` _(required)_
    - `net` `object & object | null` _(required)_
  - `payment` `object | null` _(required)_
    - `asset` `string` _(required)_
    - `chain` `string` _(required)_
    - `payerAddress` `string`
  - `merchantReference` `string | null` _(required)_
  - `metadata` `object` _(required)_: What the caller attached when it created the payment. Text a buyer may have typed.

#### `400`: `since` is not a time.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

#### `401`: Missing or unknown key.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

#### `403`: A publishable key, a secret key without `payments:read`, or a secret key sent in the URL.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

#### `429`: Too many streams are open for this merchant.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl 'https://api.mayarin.xyz/v1/payments/stream?since=string&key=string'
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/stream?since=string&key=string')
```

## Get payment status

`GET /v1/payments/{id}`

Takes a payment intent id (`pi_…`) and the payer's token, or the owning merchant's secret key.

### Path parameters

- `id` `string` _(required)_

### Responses

#### `200`: Payment, clearing state, deposit, and timeline.

Body (`application/json`):

- `paymentIntent` `object` _(required)_
  - `id` `string` _(required)_
  - `status` `string` _(required)_: Payment intent lifecycle state.
  - `merchant` `object` _(required)_
    - `id` `string` _(required)_
    - `name` `string` _(required)_
    - `city` `string` _(required)_
    - `countryCode` `string` _(required)_
    - `categoryCode` `string`
  - `amount` `object` _(required)_
    - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
    - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
    - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
    - `display` `string` _(required)_: Localized display text. Never parse this value.
  - `settlementAsset` `string` _(required)_
  - `provider` `string | null` _(required)_
  - `payment` `object | null` _(required)_
    - `asset` `string` _(required)_
    - `chain` `string` _(required)_
    - `payerAddress` `string`
  - `executionPath` `string | null` _(required)_
  - `escrow` `object | null` _(required)_: Buyer-protection escrow terms; null for an ordinary payment.
    - `holdSeconds` `integer` _(required)_
    - `arbiter` `string`
  - `source` `string` _(required)_
  - `metadata` `object` _(required)_
  - `merchantReference` `string | null` _(required)_
  - `clearingTransactionId` `string | null` _(required)_
  - `failureReason` `string | null` _(required)_
  - `createdAt` `string` _(required)_
  - `updatedAt` `string` _(required)_
  - `expiresAt` `string` _(required)_
  - `confirmedAt` `string | null` _(required)_
  - `completedAt` `string | null` _(required)_
- `clearing` `object | null` _(required)_: What clearing recorded for the payment. `null` until it is confirmed.
  - `id` `string` _(required)_
  - `state` `string` _(required)_: Clearing transaction state.
  - `provider` `string` _(required)_
  - `providerReference` `string | null` _(required)_
  - `transactionHash` `string | null` _(required)_
  - `sourceAmount` `object` _(required)_
    - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
    - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
    - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
    - `display` `string` _(required)_: Localized display text. Never parse this value.
  - `settlementAmount` `object & object | null` _(required)_
  - `fee` `object & object | null` _(required)_
  - `netAmount` `object & object | null` _(required)_
  - `rate` `object | null` _(required)_: The rate the engine locked for clearing. It is not always the price quoted to the payer: when the payer asset and the settlement asset are the same, it is 1:1. To show the payer's price for the priced currency, divide the deposit amount by `sourceAmount`.
    - `from` `string` _(required)_: Asset the rate converts from.
    - `to` `string` _(required)_: Asset the rate converts to.
    - `scaledRate` `string` _(required)_: Minor units of `to` per 1 whole unit of `from`, multiplied by 10^9. Divide by 10^9 and by 10^decimals of `to` for the whole-unit rate.
    - `source` `string` _(required)_: Where the rate came from.
    - `lockedAt` `string` _(required)_: When the rate was locked, ISO 8601.
  - `failure` `object | null` _(required)_
    - `reason` `string` _(required)_
    - `code` `string` _(required)_
    - `at` `string` _(required)_
  - `createdAt` `string` _(required)_
  - `updatedAt` `string` _(required)_
- `deposit` `object | null` _(required)_
  - `address` `string` _(required)_
  - `chain` `string` _(required)_
  - `asset` `string` _(required)_
  - `amount` `object` _(required)_
    - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
    - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
    - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
    - `display` `string` _(required)_: Localized display text. Never parse this value.
  - `uri` `string | null` _(required)_: EIP-681 payment URI for a QR, or null when none can be built safely.
  - `received` `object` _(required)_
    - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
    - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
    - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
    - `display` `string` _(required)_: Localized display text. Never parse this value.
  - `required` `integer` _(required)_
  - `reviewRequired` `boolean` _(required)_
  - `deposits` `object[]` _(required)_
    - `txHash` `string | null` _(required)_
    - `logIndex` `integer` _(required)_
    - `amount` `object` _(required)_
      - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
      - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
      - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
      - `display` `string` _(required)_: Localized display text. Never parse this value.
    - `status` `string` _(required)_
    - `confirmations` `integer` _(required)_
    - `firstSeenAt` `string` _(required)_
- `timeline` `object[]` _(required)_
  - `sequence` `integer` _(required)_
  - `state` `string` _(required)_
  - `from` `string | null` _(required)_
  - `occurredAt` `string` _(required)_

#### `404`: No payment with that id.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string')
```

## Retry a failed payment whose funds arrived

`POST /v1/payments/{id}/retry`

Reopens a `FAILED` payment at `ASSET_RECEIVED` and replays the clearing steps, for a failure since fixed (a missing swap pool, an asset not yet whitelisted) while the payer's money sat at the deposit address. Every step is idempotent per state, so nothing that already happened happens twice. A deposit-match order whose deadline passed is re-signed with the same terms and a fresh deadline. Refused with 409 when the payment has not failed or its funds never arrived.

### Path parameters

- `id` `string` _(required)_

### Responses

#### `200`: The reopened clearing transaction.

Body (`application/json`):

- `clearing` `object | null` _(required)_: What clearing recorded for the payment. `null` until it is confirmed.
  - `id` `string` _(required)_
  - `state` `string` _(required)_: Clearing transaction state.
  - `provider` `string` _(required)_
  - `providerReference` `string | null` _(required)_
  - `transactionHash` `string | null` _(required)_
  - `sourceAmount` `object` _(required)_
    - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
    - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
    - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
    - `display` `string` _(required)_: Localized display text. Never parse this value.
  - `settlementAmount` `object & object | null` _(required)_
  - `fee` `object & object | null` _(required)_
  - `netAmount` `object & object | null` _(required)_
  - `rate` `object | null` _(required)_: The rate the engine locked for clearing. It is not always the price quoted to the payer: when the payer asset and the settlement asset are the same, it is 1:1. To show the payer's price for the priced currency, divide the deposit amount by `sourceAmount`.
    - `from` `string` _(required)_: Asset the rate converts from.
    - `to` `string` _(required)_: Asset the rate converts to.
    - `scaledRate` `string` _(required)_: Minor units of `to` per 1 whole unit of `from`, multiplied by 10^9. Divide by 10^9 and by 10^decimals of `to` for the whole-unit rate.
    - `source` `string` _(required)_: Where the rate came from.
    - `lockedAt` `string` _(required)_: When the rate was locked, ISO 8601.
  - `failure` `object | null` _(required)_
    - `reason` `string` _(required)_
    - `code` `string` _(required)_
    - `at` `string` _(required)_
  - `createdAt` `string` _(required)_
  - `updatedAt` `string` _(required)_

#### `404`: No payment with that id, or it has no clearing transaction.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

#### `409`: The payment has not failed, or its funds never arrived.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string/retry \
  --request POST
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string/retry', {
  method: 'POST'
})
```

## Download the payment's invoice

`GET /v1/payments/{id}/invoice.pdf`

A one-page PDF invoice, rendered on request from the payment's immutable snapshots. An intent minted from an invoice prints that invoice's number and buyer; any other payment prints a number derived from its id.

### Path parameters

- `id` `string` _(required)_

### Responses

#### `200`: The invoice.

#### `404`: No payment with that id.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string/invoice.pdf
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string/invoice.pdf')
```

## Download the payment's receipt

`GET /v1/payments/{id}/receipt.pdf`

A one-page PDF receipt with the settlement proof: the asset paid, network, locked rate, settled amount, fee and transaction hash. Available once the payment has completed.

### Path parameters

- `id` `string` _(required)_

### Responses

#### `200`: The receipt.

#### `404`: No payment with that id.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

#### `409`: The payment has not completed yet.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string/receipt.pdf
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string/receipt.pdf')
```

## Get fresh contract call data

`GET /v1/payments/{id}/contract-call`

Returns the signed EIP-712 order, the deployed PaymentRouter address and chain, and a fresh executable route for an on-chain-contract payment. A 404 means the contract path is not enabled; a 410 means the quote lock expired — request a new payment.

### Path parameters

- `id` `string` _(required)_

### Responses

#### `200`: Signed order and submit payload.

Body (`application/json`):

- `chain` `string` _(required)_
- `chainId` `string` _(required)_
- `paymentRouter` `string` _(required)_
- `order` `object` _(required)_
  - `intentId` `string` _(required)_
  - `settlementToken` `string` _(required)_
  - `minOut` `string` _(required)_
  - `fee` `string` _(required)_
  - `merchantSafe` `string` _(required)_
  - `refundTo` `string` _(required)_
  - `deadline` `string` _(required)_
- `signature` `string` _(required)_
- `route` `object | null` _(required)_
  - `router` `string` _(required)_
  - `callData` `string` _(required)_
  - `expectedIn` `string` _(required)_
  - `expiresAt` `string`
- `transaction` `object | null` _(required)_: Ready payEth call for a native payer; null for an ERC-20 payer.
  - `to` `string` _(required)_
  - `data` `string` _(required)_
  - `value` `string` _(required)_
- `payerEstimate` `string` _(required)_
- `expiresAt` `string` _(required)_

#### `404`: Contract path not enabled, or no such payment.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

#### `410`: Quote lock expired.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string/contract-call
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string/contract-call')
```

## Get an escrowed payment's hold

`GET /v1/payments/{id}/escrow`

Where an escrowed payment's funds are, read from the chain, and the calldata to release, refund or dispute them. The escrow contract decides who may send each call: the payer releases or disputes, the merchant refunds, anyone releases once an undisputed hold ends.

### Path parameters

- `id` `string` _(required)_

### Responses

#### `200`: The escrow.

Body (`application/json`):

- `escrow` `object` _(required)_
  - `chain` `string` _(required)_
  - `chainId` `string` _(required)_
  - `factory` `string` _(required)_: EscrowFactory; send `calls[action]` here.
  - `address` `string` _(required)_: The per-payment escrow address the funds settled into.
  - `token` `string` _(required)_
  - `terms` `object` _(required)_
    - `intentId` `string` _(required)_
    - `payer` `string` _(required)_
    - `payee` `string` _(required)_
    - `arbiter` `string` _(required)_
    - `releaseAfter` `string` _(required)_: ISO time after which an undisputed escrow is releasable by anyone.
    - `resolveBy` `string` _(required)_: ISO time at which a dispute nobody decided refunds the payer.
  - `outcome` `string` _(required)_
  - `disputed` `boolean` _(required)_
  - `balance` `string` _(required)_: Settlement-token minor units still held.
  - `calls` `object` _(required)_
    - `release` `string` _(required)_
    - `refund` `string` _(required)_
    - `dispute` `string` _(required)_

#### `404`: No such payment, or it is not held in escrow.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string/escrow
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string/escrow')
```

## List refunds for a payment

`GET /v1/payments/{id}/refunds`

### Path parameters

- `id` `string` _(required)_

### Responses

#### `200`: Refund records.

Body (`application/json`):

- `id` `string` _(required)_
- `paymentIntentId` `string` _(required)_
- `amount` `object` _(required)_
  - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
  - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
  - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
  - `display` `string` _(required)_: Localized display text. Never parse this value.
- `state` `string` _(required)_
- `reason` `string | null` _(required)_
- `providerReference` `string | null` _(required)_
- `failureReason` `string | null` _(required)_
- `createdAt` `string` _(required)_
- `updatedAt` `string` _(required)_

#### `404`: No payment with that id.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string/refunds
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string/refunds')
```

## Create a refund

`POST /v1/payments/{id}/refunds`

### Path parameters

- `id` `string` _(required)_

### Header parameters

- `Idempotency-Key` `string` _(required)_: Stable unique key for this logical write. Keep it unchanged when retrying.

### Request body (`application/json`)

- `amount` `object`
  - `amount` `string` _(required)_
  - `asset` `string` _(required)_
- `reason` `string`

### Responses

#### `201`: Refund created.

Body (`application/json`):

- `id` `string` _(required)_
- `paymentIntentId` `string` _(required)_
- `amount` `object` _(required)_
  - `amount` `string` _(required)_: Exact minor units. Calculate with this value.
  - `asset` `string` _(required)_: ISO asset code, e.g. IDR, USD, USDC.
  - `formatted` `string` _(required)_: Machine decimal; ungrouped and dot-separated.
  - `display` `string` _(required)_: Localized display text. Never parse this value.
- `state` `string` _(required)_
- `reason` `string | null` _(required)_
- `providerReference` `string | null` _(required)_
- `failureReason` `string | null` _(required)_
- `createdAt` `string` _(required)_
- `updatedAt` `string` _(required)_

#### `400`: Validation error or non-refundable state.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

#### `404`: No payment with that id.

Body (`application/json`):

- `error` `object` _(required)_
  - `code` `string` _(required)_
  - `message` `string` _(required)_
  - `retryable` `boolean` _(required)_
  - `details` `object`

### Example request

```bash
curl https://api.mayarin.xyz/v1/payments/string/refunds \
  --request POST \
  --header 'Idempotency-Key: string' \
  --header 'Content-Type: application/json' \
  --data '{
  "amount": {
    "amount": "string",
    "asset": "IDR"
  },
  "reason": "string"
}'
```

```ts
fetch('https://api.mayarin.xyz/v1/payments/string/refunds', {
  method: 'POST',
  headers: {
    'Idempotency-Key': 'string',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    amount: {
      amount: 'string',
      asset: 'IDR'
    },
    reason: 'string'
  })
})
```
