{"components":{"parameters":{"IdempotencyKey":{"description":"Opaque key (\u2264 80 chars) that scopes the request for replay-detection.","in":"header","name":"Idempotency-Key","required":true,"schema":{"maxLength":80,"type":"string"}},"XSignature":{"description":"Required when the calling client has `RequireSignature` enabled.","in":"header","name":"X-Signature","required":false,"schema":{"pattern":"^sha256=[0-9a-fA-F]{64}$","type":"string"}},"XTimestamp":{"description":"Unix epoch seconds. Required when signing is enabled; drift > 300s is rejected.","in":"header","name":"X-Timestamp","required":false,"schema":{"format":"int64","type":"integer"}}},"schemas":{"AuthorizationApproved":{"properties":{"amount":{"format":"double","type":"number"},"approvalCode":{"pattern":"^\\\\d{6}$","type":"string"},"authorizationId":{"description":"7-digit human ID","type":"string"},"expires":{"format":"date-time","type":"string"},"recordId":{"description":"17-char RecordId","type":"string"},"status":{"enum":["approved"],"type":"string"}},"type":"object"},"AuthorizationDeclined":{"properties":{"amount":{"format":"double","type":"number"},"authorizationId":{"nullable":true,"type":"string"},"details":{"additionalProperties":true,"type":"object"},"reasonCode":{"type":"string"},"reasonMessage":{"type":"string"},"recordId":{"nullable":true,"type":"string"},"status":{"enum":["declined"],"type":"string"}},"type":"object"},"AuthorizationRead":{"properties":{"acknowledged":{"format":"date-time","nullable":true,"type":"string"},"amount":{"format":"double","type":"number"},"approvalCode":{"nullable":true,"type":"string"},"authorizationId":{"type":"string"},"avsResult":{"nullable":true,"type":"string"},"captured":{"format":"double","type":"number"},"card":{"type":"string"},"channel":{"nullable":true,"type":"string"},"created":{"format":"date-time","nullable":true,"type":"string"},"currency":{"type":"string"},"cvvResult":{"nullable":true,"type":"string"},"expires":{"format":"date-time","nullable":true,"type":"string"},"mcc":{"nullable":true,"type":"string"},"merchant":{"nullable":true,"type":"string"},"merchantNameRaw":{"nullable":true,"type":"string"},"mode":{"nullable":true,"type":"string"},"reasonCode":{"nullable":true,"type":"string"},"reasonTitle":{"nullable":true,"type":"string"},"recordId":{"type":"string"},"responseCode":{"nullable":true,"type":"string"},"reversed":{"format":"double","type":"number"},"settled":{"format":"date-time","nullable":true,"type":"string"},"status":{"description":"e.g. \"Authorization Approved\"","type":"string"}},"type":"object"},"AuthorizationRequest":{"properties":{"amount":{"example":12.99,"format":"double","minimum":0.01,"type":"number"},"avsResult":{"enum":["Y","N","A","Z","U"],"type":"string"},"channel":{"description":"`Issuing.Channels.RecordId` \u2014 POS / ECOMM / etc.","type":"string"},"currency":{"description":"`Core.Currencies.RecordId`. Defaults to USD.","type":"string"},"cvvResult":{"enum":["M","N","P","U","X"],"type":"string"},"mcc":{"pattern":"^\\\\d{4}$","type":"string"},"merchant":{"description":"`Merchant.Accounts.RecordId`.","type":"string"},"merchantNameRaw":{"description":"Statement-style name the merchant sent.","maxLength":64,"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"mode":{"description":"`01` card-present \u00b7 `02` CNP \u00b7 `03` recurring \u00b7 `04` token \u00b7 `05` MOTO","enum":["01","02","03","04","05"],"type":"string"},"panToken":{"description":"Opaque card token (`Issuing.Tokens.RecordId`). The PAN itself never traverses this API.","maxLength":17,"minLength":17,"type":"string"}},"required":["panToken","amount"],"type":"object"},"CaptureRequest":{"description":"Omit `amount` to capture the full remaining hold.","properties":{"amount":{"format":"double","minimum":0.01,"type":"number"}},"type":"object"},"CaptureResponse":{"properties":{"acknowledged":{"format":"date-time","nullable":true,"type":"string"},"amountCaptured":{"format":"double","type":"number"},"authorizationId":{"type":"string"},"idempotencyKey":{"type":"string"},"recordId":{"type":"string"},"settled":{"format":"date-time","nullable":true,"type":"string"},"status":{"enum":["charged","partial"],"type":"string"}},"type":"object"},"Error":{"properties":{"error":{"properties":{"code":{"description":"Stable machine identifier. ISO-8583 numeric codes (`14`, `54`, `61`, `62`, `65`, `75`) appear on card/code declines.","example":"54","type":"string"},"details":{"additionalProperties":true,"type":"object"},"field":{"nullable":true,"type":"string"},"message":{"example":"Card expired","type":"string"}},"required":["code","message"],"type":"object"}},"required":["error"],"type":"object"},"IncrementRequest":{"properties":{"amount":{"format":"double","minimum":0.01,"type":"number"},"metadata":{"additionalProperties":true,"type":"object"}},"required":["amount"],"type":"object"},"IncrementResponse":{"properties":{"amount":{"format":"double","type":"number"},"approvalCode":{"type":"string"},"authorizationId":{"type":"string"},"expires":{"format":"date-time","type":"string"},"parentAuthorization":{"type":"string"},"recordId":{"type":"string"},"status":{"enum":["approved"],"type":"string"}},"type":"object"},"Me":{"properties":{"apiKey":{"type":"string"},"created":{"format":"date-time","nullable":true,"type":"string"},"environment":{"enum":["live","test"],"type":"string"},"id":{"type":"string"},"lastUsed":{"format":"date-time","nullable":true,"type":"string"},"rateLimitTier":{"type":"string"},"requireSignature":{"type":"boolean"},"secretLast4":{"maxLength":4,"minLength":4,"type":"string"},"slug":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"}},"type":"object"},"PaymentCodeAuthorizeRequest":{"properties":{"amount":{"format":"double","minimum":0.01,"type":"number"},"code":{"maxLength":10,"minLength":10,"type":"string"},"currency":{"type":"string"},"deviceFingerprint":{"type":"string"},"merchant":{"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"pin":{"maxLength":7,"minLength":7,"type":"string"}},"required":["code","pin","amount","merchant"],"type":"object"},"PaymentCodeAuthorizeResponse":{"properties":{"account":{"nullable":true,"type":"string"},"amount":{"format":"double","type":"number"},"authorizationId":{"nullable":true,"type":"string"},"expires":{"format":"date-time","nullable":true,"type":"string"},"member":{"nullable":true,"type":"string"},"reasonCode":{"nullable":true,"type":"string"},"reasonMessage":{"nullable":true,"type":"string"},"recordId":{"nullable":true,"type":"string"},"status":{"enum":["approved","declined"],"type":"string"}},"type":"object"},"PaymentCodeCreateRequest":{"properties":{"account":{"type":"string"},"allowRecurring":{"default":false,"type":"boolean"},"currency":{"type":"string"},"displayHint":{"maxLength":64,"type":"string"},"expiryMinutes":{"default":10,"minimum":1,"type":"integer"},"lockoutThreshold":{"default":5,"type":"integer"},"maxAmount":{"format":"double","type":"number"},"member":{"description":"`Relationship.Accounts.RecordId`","type":"string"},"merchant":{"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"recurringInterval":{"enum":["daily","weekly","monthly"],"type":"string"},"recurringLimit":{"type":"integer"},"recurringThru":{"format":"date","type":"string"},"singleUse":{"default":true,"type":"boolean"}},"required":["member"],"type":"object"},"PaymentCodeCreated":{"properties":{"code":{"description":"10-char Crockford alphabet","type":"string"},"expiresAt":{"format":"date-time","type":"string"},"pin":{"description":"7-char Crockford alphabet \u2014 returned ONCE only","type":"string"},"recordId":{"type":"string"},"status":{"enum":["Code Active"],"type":"string"}},"type":"object"},"ReverseRequest":{"properties":{"amount":{"description":"Defaults to full remaining hold or full captured amount.","format":"double","minimum":0.01,"type":"number"},"reason":{"default":"RV02","description":"Issuing.Reasons.Code (default `RV02` customer void).","type":"string"}},"type":"object"},"ReverseResponse":{"properties":{"amountReversed":{"format":"double","type":"number"},"authorizationId":{"type":"string"},"idempotencyKey":{"type":"string"},"reasonCode":{"type":"string"},"recordId":{"type":"string"},"settled":{"format":"date-time","nullable":true,"type":"string"},"status":{"enum":["reversed","partial-reversed"],"type":"string"}},"type":"object"},"WebhookDelivery":{"properties":{"attempt":{"type":"integer"},"created":{"format":"date-time","nullable":true,"type":"string"},"deliveredAt":{"format":"date-time","nullable":true,"type":"string"},"error":{"nullable":true,"type":"string"},"event":{"type":"string"},"id":{"type":"string"},"nextRetryAt":{"format":"date-time","nullable":true,"type":"string"},"responseCode":{"nullable":true,"type":"integer"},"scheduledAt":{"format":"date-time","nullable":true,"type":"string"},"status":{"description":"e.g. \"Webhook Delivered\"","type":"string"},"url":{"format":"uri","type":"string"}},"type":"object"},"WebhookSubscription":{"properties":{"created":{"format":"date-time","type":"string"},"description":{"nullable":true,"type":"string"},"events":{"items":{"type":"string"},"type":"array"},"failureCount":{"type":"integer"},"id":{"type":"string"},"lastDelivery":{"format":"date-time","nullable":true,"type":"string"},"secret":{"description":"Only present on create + rotate-secret.","type":"string"},"secretLast4":{"maxLength":4,"minLength":4,"type":"string"},"status":{"enum":["active","paused","revoked"],"type":"string"},"updated":{"format":"date-time","nullable":true,"type":"string"},"url":{"format":"uri","type":"string"}},"type":"object"},"WebhookSubscriptionCreate":{"properties":{"description":{"maxLength":256,"type":"string"},"events":{"items":{"enum":["authorization.approved","authorization.declined","authorization.captured","authorization.reversed"],"type":"string"},"minItems":1,"type":"array"},"url":{"example":"https://merchant.example.com/webhooks","format":"uri","maxLength":2048,"type":"string"}},"required":["url","events"],"type":"object"},"WebhookSubscriptionUpdate":{"properties":{"description":{"maxLength":256,"type":"string"},"events":{"items":{"enum":["authorization.approved","authorization.declined","authorization.captured","authorization.reversed"],"type":"string"},"minItems":1,"type":"array"},"status":{"enum":["active","paused"],"type":"string"},"url":{"format":"uri","maxLength":2048,"type":"string"}},"type":"object"}},"securitySchemes":{"apiKey":{"description":"Tenant public identifier. `pk_live_\u2026` for production or `pk_test_\u2026` for sandbox.","in":"header","name":"X-API-Key","type":"apiKey"},"bearerAuth":{"bearerFormat":"opaque","description":"Tenant secret. Stored bcrypt-hashed; compared inside the DB via `pgcrypto.crypt()`.","scheme":"bearer","type":"http"}}},"info":{"contact":{"name":"developer.rmous.org","url":"https://developer.rmous.org"},"description":"The RMO Network is a closed-loop payment network. We are both the\nacquirer (we onboard merchants) and the issuer (we issue cards and\npayment codes). The public API surface at `api.rmous.org/v1/*` is\nwhat merchants, processors, and developers call to authorize,\ncapture, reverse, and refund transactions.\n\n## Authentication\n\nEvery mutating request requires three headers:\n\n| Header | Purpose |\n|---|---|\n| `X-API-Key: pk_live_\u2026` / `pk_test_\u2026` | Public tenant identifier |\n| `Authorization: Bearer sk_\u2026` | Tenant secret (bcrypt-compared inside the DB, never echoed) |\n| `Idempotency-Key: <opaque>` | Required on writes \u2014 replays are returned, not re-executed |\n\nOptionally (per-client setting `RequireSignature`):\n\n| Header | Purpose |\n|---|---|\n| `X-Signature: sha256=<hex>` | HMAC-SHA256 of `METHOD\\nPATH\\nTIMESTAMP\\nBODY` using the bearer secret |\n| `X-Timestamp: <unix>` | Rejected if drift exceeds 300s |\n\n## PCI posture\n\nThe host serving `/v1/*` has no AWS Payment Cryptography permissions\nand never sees a raw PAN. Cards are addressed exclusively by opaque\n17-character `panToken` values. PINs for payment codes are bcrypt-\nhashed in the database \u2014 the plaintext is only seen at create time\nand at redemption.\n\n## Webhook signatures\n\nWhen the worker delivers an outbound event, it signs the body with\nthe subscription's signing secret:\n\n```\nX-RMO-Signature: sha256=<hex>     # HMAC-SHA256 of timestamp + \".\" + body\nX-RMO-Timestamp: <unix>\nX-RMO-Event:     authorization.approved\nX-RMO-Delivery:  <delivery RecordId>\nIdempotency-Key: <event-type>:<source idempotency key>\n```\n\nVerify the signature and the timestamp drift to reject replays.\n","summary":"Public payments API for the RMO Network \u2014 card authorizations, payment codes, and webhook subscriptions.","title":"RMO Network API","version":"0.2.0"},"openapi":"3.1.0","paths":{"/v1/authorizations":{"post":{"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/XSignature"},{"$ref":"#/components/parameters/XTimestamp"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizationRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AuthorizationDeclined"},{"$ref":"#/components/schemas/AuthorizationApproved"}]}}},"description":"Declined (or idempotent replay of a prior request)."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizationApproved"}}},"description":"Approved"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Validation error"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Auth failed"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid `panToken`"}},"summary":"Submit a card authorization."}},"/v1/authorizations/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizationRead"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"}},"summary":"Read an authorization by `Id` (7-digit) or `RecordId` (17-char)."}},"/v1/authorizations/{id}/capture":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureResponse"}}},"description":"Capture applied"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Auth not in a capturable state"}},"summary":"Capture (full or partial). Omitting `amount` captures the remainder."}},"/v1/authorizations/{id}/increment":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrementRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrementResponse"}}},"description":"Incremental approved"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Parent auth not in `Authorization Approved` state"}},"summary":"Incremental authorization \u2014 hotels / gas / ride-share."}},"/v1/authorizations/{id}/reverse":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReverseRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReverseResponse"}}},"description":"Reverse applied"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Auth not in a reversible state"}},"summary":"Void (pre-capture) or refund (post-capture)."}},"/v1/health":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"service":{"type":"string"},"status":{"enum":["ok"],"type":"string"},"version":{"type":"string"}},"type":"object"}}},"description":"OK"}},"security":[],"summary":"Liveness probe \u2014 unauthenticated."}},"/v1/me":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}},"description":"OK"}},"summary":"Get the calling tenant's identity & limits."}},"/v1/payment-codes":{"post":{"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentCodeCreateRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentCodeCreated"}}},"description":"Created. `pin` is returned ONCE."}},"summary":"Mint a payment code + PIN on behalf of a member."}},"/v1/payment-codes/authorize":{"post":{"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentCodeAuthorizeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentCodeAuthorizeResponse"}}},"description":"Declined"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentCodeAuthorizeResponse"}}},"description":"Approved"}},"summary":"Merchant redeems `code + pin + amount`."}},"/v1/payment-codes/{code}":{"get":{"parameters":[{"in":"path","name":"code","required":true,"schema":{"maxLength":10,"minLength":10,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object"}}},"description":"OK"}},"summary":"Read a payment-code's state. PIN is never returned."}},"/v1/payment-codes/{code}/revoke":{"post":{"parameters":[{"in":"path","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"reason":{"type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"recordId":{"type":"string"},"revoked":{"type":"boolean"}},"type":"object"}}},"description":"Revoked"}},"summary":"Revoke a payment code."}},"/v1/webhook-subscriptions":{"get":{"parameters":[{"in":"query","name":"limit","schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}},{"in":"query","name":"starting_after","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"enum":["active","paused","revoked"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookSubscription"},"type":"array"},"hasMore":{"type":"boolean"}},"type":"object"}}},"description":"OK"}},"summary":"List webhook subscriptions for the calling tenant."},"post":{"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionCreate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}},"description":"Idempotent replay \u2014 `secret` will not be returned."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}},"description":"Created"}},"summary":"Create a webhook subscription. `secret` is returned ONCE."}},"/v1/webhook-subscriptions/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"id":{"type":"string"},"revoked":{"type":"boolean"}},"type":"object"}}},"description":"Revoked"}},"summary":"Soft revoke. The worker stops delivering new events."},"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found"}},"summary":"Read one webhook subscription."},"patch":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}},"description":"Updated"}},"summary":"Update url / events / description / status."}},"/v1/webhook-subscriptions/{id}/deliveries":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}},{"in":"query","name":"starting_after","schema":{"type":"string"}},{"in":"query","name":"event","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookDelivery"},"type":"array"},"hasMore":{"type":"boolean"}},"type":"object"}}},"description":"OK"}},"summary":"Recent delivery attempts (debug visibility)."}},"/v1/webhook-subscriptions/{id}/rotate-secret":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}},"description":"Rotated. `secret` is the new signing key."}},"summary":"Mint a new signing secret. Returned ONCE in the response."}}},"security":[{"apiKey":[],"bearerAuth":[]}],"servers":[{"description":"Production","url":"https://api.rmous.org"},{"description":"Sandbox (use `pk_test_\u2026` API keys)","url":"https://api.rmous.org"}]}
