API Overview
The Owem Pay API lets you integrate PIX payments into your system. All operations require API Key and IP Whitelist; POST endpoints additionally require HMAC-SHA512 over the body.
Base URL
| Environment | URL |
|---|---|
| Production | https://api.owem.com.br |
| Homologation | https://api-hml.owem.com.br |
Authentication
Security layers (per request type):
- IP Whitelist (all) -- Source IP must be in the whitelist configured on the API Key
- API Key (all) -- Header
Authorization: ApiKey {client_id}:{client_secret}on every request - HMAC-SHA512 (only
POST) -- Request body signature; required onPOST /pix/cash-in,POST /pix/cash-out,POST /cpf/validate,POST /webhooks,POST /pix/refund.GETandDELETErequests do not carry HMAC (they have no body to sign).
Mandatory alphabetical order in HMAC body
POST requests that require HMAC must sign the body with keys in alphabetical order. The backend runs Jason.decode + Jason.encode! on the body for validation, which reorders the keys. If your client does not alphabetize before signing, the locally computed HMAC will not match the server → HTTP 401.
Full details: HMAC-SHA512.
See Authentication and HMAC-SHA512 for details.
Format
| Field | Format |
|---|---|
| Content-Type | application/json |
| Request values | Integers in centavos (R$ 1.00 = 100) |
| Response values | Integers in subcentavos (base units; R$ 1.00 = 10000, ÷ 10,000 for BRL) |
| Dates | ISO 8601 in UTC with Z suffix (2026-03-09T15:30:00Z) |
| IDs | UUID v4 or alphanumeric string |
| E2E ID | ^E\d{8}[a-zA-Z0-9]{22,26}$ (BACEN standard, 31-35 chars, suffix may contain letters) |
Terminology
In this documentation, subcentavos and base units refer to the same unit (10,000 = R$ 1.00). The term "base units" appears in some inherited examples; consider it synonymous with subcentavos. Always divide the response value by 10,000 to get BRL.
E2E may contain letters
The suffix after E + ISPB + timestamp is alphanumeric, 9 to 13 characters long (not only digits). Banks like Nubank emit E2Es with letters at the end. Always validate with the full regex. Details in PIX Cash-In by E2E ID.
Value conversion
To send: multiply BRL by 100. R$ 1.00 = 100. To read responses: divide by 10,000. 10000 ÷ 10,000 = R$ 1.00. Never use floating point -- always integers.
Key case (optional camelCase)
JSON responses use snake_case by default (e.g., transaction_id, end_to_end_id). If your client prefers camelCase, send the header:
X-Key-Case: camelCaseThe backend converts all keys of the JSON response (including nested objects) automatically. Example: transaction_id → transactionId, pix_key_type → pixKeyType. The header does not affect the input body — always send it in snake_case on POST.
Response Pattern
Success
{
"worked": true,
"transaction_id": "PIXOUT20260309abcdef123456",
"status": "processing"
}Error
The error shape varies by the layer that rejected the request:
// HMAC plug (401 invalid signature)
{ "worked": false, "detail": "Invalid HMAC signature" }
// ApiKeyAuth (401 / 403)
{ "error": { "status": 401, "message": "Invalid API key" } }
// FallbackController (404 / 400 / 409 / 422 / 500 — business cases)
{ "errors": { "not_found": "transaction not found" } }See the full table at Authentication -- Error Responses.
HTTP Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Resource created (webhook) |
| 400 | Invalid parameters |
| 401 | Missing or invalid API Key / Invalid HMAC |
| 403 | IP not authorized in whitelist |
| 404 | Resource not found |
| 422 | Validation failed (insufficient balance, invalid key) |
| 429 | Rate limit exceeded |
| 500 | Internal error |
Rate Limiting
| Type | Limit |
|---|---|
| Per IP (authenticated) | 90,000 requests/minute (1,500 req/s) |
| Per IP (authentication / login) | 5 requests/minute |
GET /balance | no rate limit (high-frequency polling allowed) |
Response headers:
X-RateLimit-Remaining: 59997
Retry-After: 3 (only when 429)Idempotency
POST requests accept the Idempotency-Key header (max 256 characters) to prevent duplicate processing. Only 2xx (success) responses are cached for 24 hours. If the same key is resent for the same method and endpoint, the API returns the original response with the header X-Idempotent-Replay: true.
Idempotency-Key: unique-request-id-123Key scope
The key is bound to method + path + Idempotency-Key. The same key can be reused in different endpoints without collision. Error responses (4xx/5xx) are not cached -- the client can retry after fixing the failure.
GET/DELETE and Idempotency-Key
GET and DELETE requests silently ignore the Idempotency-Key header -- the plug only acts on POST. Sending the key on these methods does not cause an error, but generates no cache or replay.
Retry and quarantine policies
- Quarantine (stage=5): A PIX Cash-Out stuck in
status: "processing"for more than 30 minutes is moved to quarantine, where it stays awaiting manual resolution by the Owem team. The status remains"processing"from the client's perspective until finalization. Details in the flow: PIX Lifecycle. - Automatic webhook retry: failed deliveries (timeout, 5xx, closed connection) are rescheduled for up to 7 attempts (intervals
[0, 30s, 2min, 10min, 30min, 1h, 2h, 4h]). See Webhooks. - Client retry: upon receiving
429, honorRetry-After. Upon receiving500or timeout, use exponential backoff +Idempotency-Keyto avoid duplication. See Authentication for details. - Webhook anti-replay window: the
X-Owem-Timestampheader is Unix time in seconds. The server does not reject old webhooks; it is up to your endpoint to discard deliveries with|now - timestamp| > 300s(± 5 minutes) as defense-in-depth against replay. See Webhooks -- Signature Validation.
External ID
Optional external_id field (max 128 chars, alphanumeric + ._:-) accepted in cash-in and cash-out. Returned in responses and webhooks. Allows lookup by reference:
GET /api/external/transactions/ref/{external_id}Endpoints
PIX Cash Out (Send)
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/external/pix/cash-out | Send PIX by key or copy-and-paste |
PIX Cash In (Receive)
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/external/pix/cash-in | Generate QR Code for receiving |
Queries
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/external/transactions | List transactions |
| GET | /api/external/transactions/:id | Query transaction by ID |
| GET | /api/external/transactions/e2e/:e2e_id | Query by E2E ID |
| GET | /api/external/transactions/tag/:tag | Query by tag (prefix) |
| GET | /api/external/transactions/ref/:external_id | Query by external_id |
| GET | /api/external/transactions/:id/receipt | Receipt |
Account
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/external/balance | Account balance |
| GET | /api/external/statement | Statement |
PIX Keys
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/external/pix/keys | List account PIX keys |
Refund
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/external/pix/refund | PIX refund (total or partial) |
MED
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/external/med | List MEDs |
| GET | /api/external/med/:id | MED details |
Validation
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/external/cpf/validate | Validate CPF |
Webhooks
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/external/webhooks | List webhooks |
| POST | /api/external/webhooks | Register webhook |
| DELETE | /api/external/webhooks/:id | Remove webhook |