Skip to main content
The PointZero Fiat API lets you accept fiat payments (payins), send funds to cards (payouts) and track every operation on a single organization account. This page covers the full integration: where card_id comes from, the four integration scenarios, statuses, fees, webhooks, sandbox testing and the go-live checklist.
The Fiat API (version 1.1.0) uses its own base URLs and API keys (pz_live_, pz_test_). They are separate from the Card Issuing API.

Overview

Payins and payouts are part of one fiat product but are separate API operations: Both operations work with the same organization account, the same balance and the same API keys. In the PointZero dashboard all operations (payins, payouts and card operations) are shown in one history and can be filtered by operation type. The same data is available through GET /transactions.

Core objects

Where card_id comes from

PointZero does not issue cards for fiat operations. The card already exists: it is the customer’s own bank card, and the customer enters its details in your interface.
1

Customer enters card details

Your customer enters card details in your app.
2

Register the card

You send them to POST /cards.
3

PointZero returns a card_id

PointZero registers the card, generates a card_id and returns it together with the masked card data (first6, last4, brand, currency, country, expiry).
4

Store the card_id

You store the card_id against your customer.
5

Use it for payouts

You pass that card_id in every payout (and optionally in a payment) that should send funds to this card.
A registered card can be reused for any number of payouts until it expires or is deleted. Do not register the same card again for every operation. If the same card number is submitted again for the same external_customer_id, PointZero returns the existing card_id with 200 instead of 201.
Register a card
Response 201
Card statuses: active (can receive payouts), expired (expiry date has passed), inactive (deleted by you or disabled by PointZero).

Integration scenarios

Use this when the customer is only receiving money, for example after selling an asset on your platform.
Payouts to cards are completed within 15 minutes of creation (see Service levels).
amount + fee is reserved on the balance immediately. If the payout fails or is cancelled, the reserved funds are returned.

Payment methods

Override the expiry with expires_in (300 to 604800 seconds). Available methods depend on your contract.

Edge cases

Environments and authentication

Sandbox and production are fully isolated. Cards, payments, payouts and balances created in one environment are not visible in the other. All requests are authenticated with an API key sent as a Bearer token:
One API key gives access to all endpoints of your organization account: payments, payouts, cards, balances, transactions, events and limits. There are no separate keys for payins and payouts. API keys are created and revoked in the dashboard under Settings → API keys. Keep keys on your server only. Never put them in a mobile app or browser code. If a key is exposed, revoke it and create a new one; existing operations are not affected. Requests without a key or with an invalid key return 401. Requests to a resource that belongs to another organization return 404.

Requests and responses

Amounts are decimal strings with up to two decimal places, for example "1000.00". Do not send amounts as numbers: floating point values lose precision.
Currencies use ISO 4217 codes (EUR, USD). Countries use ISO 3166-1 alpha-2 codes (ES, DE). Supported currencies, payment methods and countries depend on your contract and are returned by GET /limits.All timestamps are in UTC, ISO 8601 format: 2026-09-21T12:07:31Z.
Every payment and payout accepts external_id, your own identifier for the operation (order ID, withdrawal ID). It is returned in responses and webhooks and can be used as a filter in list endpoints. external_id must be unique per operation type.metadata accepts up to 20 key-value pairs (keys up to 40 characters, values up to 500 characters). PointZero stores it and returns it without changes.
List endpoints use cursor pagination with limit (1 to 100, default 20) and starting_after (ID of the last item from the previous page).
To get the next page, pass the id of the last item in data as starting_after. Items are sorted by created_at, newest first.
POST requests that create objects (/payments, /payouts, /cards) and cancel operations accept an Idempotency-Key header.
  • If a request with the same key and the same body is repeated, PointZero returns the original response and does not create a new object.
  • If the same key is reused with a different body, PointZero returns 409 idempotency_key_reused.
  • Keys are stored for 24 hours.
  • Use your own operation ID (order ID, withdrawal ID) or a UUID.
Always send an Idempotency-Key for payouts. It is the only safe way to retry a payout request after a timeout or network error.

FX and fees

If the payout currency differs from the card currency, PointZero converts the funds at the rate applied when the payout is processed. The payout object shows the result:
credited_amount = amount × exchange_rate, rounded to two decimal places. The card currency is returned in the card object (currency), so you can show the customer which currency the card will receive. Fees are set in your contract and returned in each object. Example, Scenario B, EUR 1,000 to a USD card with a fee of EUR 10:

Statuses

Only pending payments can be cancelled with POST /payments/{payment_id}/cancel. If funds arrive after cancellation, they are returned to the sender.
Treat only succeeded as a completed operation. A successfully created payment or payout (201 response) means that the operation was accepted, not that money has moved.

Service levels

Time spent in compliance_review is not counted toward the payout SLA. Each payout includes expected_completion_at so you can show the customer when to expect the funds.

Balances and transactions

GET /balances returns the organization balance in each currency. This is the same balance shown in the dashboard and used for payouts. GET /transactions returns the operation history. Filter by type, currency or source_id (the payment or payout ID). Amounts are positive for credits and negative for debits; net is the actual change of the balance.

Webhooks

PointZero sends a webhook every time a payment, payout or card changes status. Webhooks are the main way to learn about results. Polling should only be used for reconciliation.

Setup

Add your endpoint URL in the dashboard under Settings → Webhooks, for example https://client.com/api/pointzero/webhooks. The endpoint must use HTTPS. After saving, the dashboard shows the webhook signing secret (whsec_...). Sandbox and production have separate endpoints and secrets.

Delivery

  • Respond with any 2xx status within 10 seconds. Process the event asynchronously if your handling takes longer.
  • Any other response or a timeout counts as a failed delivery. PointZero retries with increasing intervals for up to 24 hours.
  • Events may arrive more than once and not always in order. Use the event id to skip duplicates, and compare data.status with what you already have stored instead of relying on arrival order.
  • Failed deliveries can be viewed and resent from the dashboard. All events for the last 30 days are also available through GET /events.

Signature verification

The signature is an HMAC-SHA256 hex digest of the string {X-PointZero-Timestamp}.{raw request body}, using your webhook signing secret as the key.
  1. Read the raw request body before any JSON parsing.
  2. Build the signed string: timestamp, a dot, the raw body.
  3. Compute HMAC-SHA256 with your signing secret.
  4. Compare with X-PointZero-Signature using a constant-time comparison.
  5. Reject the request if the timestamp is more than 5 minutes old.

Event types

The data field of every event contains the full object (payment, payout or card) in the same format as the API response.

Compliance

Depending on the jurisdiction, payment method and amount, PointZero may need additional information before an operation can be completed:
  • customer identification (name, date of birth, address, country);
  • KYC or KYB data;
  • source of funds information;
  • sanctions and transaction screening results.
Pass the customer object in payments and payouts. external_customer_id is required; other fields help avoid compliance_review. Missing data does not block creation but can move an operation to compliance_review. While an operation is in review, the funds are held and no action from your side is needed unless the PointZero compliance team contacts you. The review ends with a *.succeeded, *.processing or *.failed event.
POST /cards accepts the full card number. Sending card numbers from your servers requires PCI DSS compliance on your side. Confirm your PCI DSS status with PointZero before going live. PointZero never returns the full card number: responses contain only first6 and last4.

Limits and rate limiting

Limits depend on country, payment method, currency, operation type, customer and card. Read the current values with GET /limits and validate amounts in your interface before creating an operation. Pass card_id or external_customer_id to get the remaining amount for that card or customer today. If a limit is exceeded, the API returns 422 limit_exceeded and the error.param field names the limit. Request limits are set per organization. Every response includes:

Errors

Errors have the same format on every endpoint. Include request_id when contacting PointZero support.
When a payment or payout ends in failed, the object contains failure_code and failure_message.

Sandbox testing

The sandbox behaves like production but does not move real money. Use pz_test_ keys and the sandbox base URL. Each sandbox organization starts with a balance of 100,000.00 EUR and 100,000.00 USD. Successful sandbox payments add to it.

Test cards for payouts

Any future expiry date and any holder name can be used.

Simulating payments

Bank transfers do not happen in the sandbox. Move a payment to the status you need with POST /sandbox/payments/{payment_id}/simulate. Webhooks are sent as in production. To test underpayment or overpayment by bank transfer, pass received_amount together with status: succeeded.
Allowed statuses: processing, compliance_review, succeeded, failed (with an optional failure_code) and expired.

Go-live checklist

  • Production API key created and stored on the server only
  • Production webhook endpoint added, signing secret stored
  • Webhook signature and timestamp verified
  • Duplicate events skipped by event id
  • Idempotency-Key sent on every POST, retries reuse the same key
  • card_id stored per customer, cards reused instead of re-registered
  • All payment and payout statuses handled, including compliance_review and reversed
  • received_amount and net_amount used for bank transfers
  • insufficient_balance handled for payouts
  • Limits checked before creating operations
  • Error handling with request_id logged
  • Reconciliation job using GET /transactions or GET /events
  • Customer data passed for compliance where required
  • PCI DSS status confirmed with PointZero
  • All scenarios tested in the sandbox

FAQ

No. They are one fiat product with two separate API operations: POST /payments for payins and POST /payouts for payouts.
No. One API key works for all endpoints of your organization account.
No. There is one organization account with a shared balance and one operation history. Payins, payouts and card operations are separated by operation type.
PointZero does not issue cards for fiat operations. The customer enters an existing card in your app, you register it with POST /cards, and PointZero returns the card_id together with the masked card data. You store it and use it as the payout destination.
Register the customer’s card with POST /cards to get a card_id, then create a payout with POST /payouts. No payment is needed. The payout is completed within 15 minutes.
No. Pass it only if the funds from this payment should go to a card automatically (Scenario B). Without it, the funds stay on your balance.
No. The card belongs to the customer’s bank, so its balance is not available. Use the payout status to confirm that funds were credited.
The payout.succeeded webhook, or status: succeeded in GET /payouts/{payout_id}.
The amount and the fee are returned to your available balance. A payout_refund transaction appears in GET /transactions.

Versioning and changelog

The version is part of the URL (/v1). Within a version PointZero may add new endpoints, optional request fields, response fields, enum values and event types. Your integration should ignore unknown fields and handle unknown enum values gracefully. Breaking changes are released only in a new version, with advance notice. Questions about your integration: hi@pointzero.com.