External transaction references and CAD collection references
- Transaction list and detail responses include
external_referencefor collections and payouts in all currencies. The field isnullwhen no reference is available or for other transaction types. - CAD collection webhooks include
interac_reference. See the CAD collection webhook guide for examples. - Completed CAD payout webhooks keep
interac_reference. Payout-initiated webhooks do not include either reference field.
Interac auto-deposit registration through the API
Submit an email for registration, list your registrations, or read one registration by ID. See Interac Auto Deposits for the complete flow.
- The new endpoints use
/api/external/interac-auto-deposit-email. Registration needs a CAD wallet and starts withPENDINGstatus. - New OAuth scopes:
interac-auto-deposit-email:createandinterac-auto-deposit-email:read. Both belong tofull-accessandcollections. Theread-onlybundle includes the read scope. - The registration status webhook guide
documents the existing
ACTIVEandBLOCKEDnotifications. These events use synchronous delivery without automatic retries, logs, or replay.
Clearer cancels and rejection reasons for Merchant KYC
- A cancel on a session that is already terminal now fails with
422. A cancelled session answersThis session has already been cancelled.An approved, rejected or expired session answersThis session has already reached a final state and cannot be cancelled.Before this change a repeat cancel answered200. - A cancel now closes the person’s verification page. After a cancel the person cannot continue or upload documents.
rejection_reasonis set on everyRETRYABLErejection. When the provider sends no comment, Blaaiz derives plain sentences from the rejection labels that tell the person what to correct. AFINALrejection carries one fixed sentence.
Two fulfilment modes for Merchant KYC
A verification session now has two fulfilment modes. You choose the shape of the flow. Blaaiz chooses the page that hosts it.
fulfilment_modetakesHOSTEDorHEADLESS. The valuesSUMSUB_HOSTEDandBLAAIZ_HOSTEDare removed. A request that sends one of them fails with422.- A
HOSTEDcreate response always carriesverification_linkandlink_expires_at. Send the link to the person you verify. AHEADLESSsession returnsnullfor both fields. POST /compliance/kyc/sessions//verification-linkreplacesPOST /compliance/kyc/sessions//capture-link. It returnsverification_linkandlink_expires_at. The fieldscapture_urlandexpires_atare removed from that response.- Blaaiz decides which page a
HOSTEDsession uses. The choice is the same for every session of one business, and the API never names it. - See the Merchant KYC overview for the supported requirement sets per mode, and the hosted quickstart for the new flow.
Interac reference in completed CAD payout webhooks
Use the Interac reference number to identify a completed CAD payout.
- The completed CAD payout webhook
includes a top-level
interac_referencestring. The value isnullwhen no reference is available. - The
payout_initiatedwebhook does not include this field. The existingextras.interac_instructionfield is unchanged.
Filter crypto wallet addresses by customer
List the crypto deposit addresses for one customer on a business wallet.
- GET /crypto/wallets//addressesaccepts an optional
customer_idquery parameter. The response includes only the addresses for that customer. - Without
customer_id, the response includes every address on the wallet, as before.
Customer crypto wallet addresses
Create static crypto wallet addresses for your business customers through API Services. Blaaiz credits the business wallet when an address receives funds.
- Create business crypto wallets in the Blaaiz dashboard. UsePOST /crypto/wallets//addressesto create customer wallet addresses.
- The request needs a
customer_id. The customer must belong to your business, have aVERIFIEDstatus, and not be under Enhanced Due Diligence. - The
crypto.deposit.successfulwebhook now includescustomer_idwhen it credits a customer wallet address.
Send your own reference on payouts and collections
You can now send your own reference on a payout or a collection. Blaaiz stores the value, returns it, and lets you find the transaction by it. You no longer have to keep a map between your order or invoice ID and the Blaaiz transaction ID.
- POST /payout and
POST /collection
accept an optional
merchant_reference. Any string up to 255 characters is valid. - Each
merchant_referencemust be unique for your business. A value that one of your earlier transactions already uses returns422. Two different businesses can use the same value. - Transaction responses now include
merchant_reference. Use the new filter on POST /transaction to list the transaction with that value. - GET /transaction/
now accepts your
merchant_referencein place of the transaction ID. - The collection, payout and payout-initiated webhooks now carry
merchant_reference. The value isnullwhen you supplied no reference.
Crypto API: customer payouts and deposit webhooks
Crypto payouts now identify the business customer that the payout is for. Blaaiz also sends a webhook when it credits a business crypto wallet from an on-chain deposit.
- POST /crypto/payouts
now needs a
customer_id. The customer must belong to your business and have aVERIFIEDstatus. - Crypto transaction responses now include
customer_id. Use the optionalcustomer_idfilter to list that customer’s crypto transactions. - Blaaiz sends
crypto.deposit.successfulto yourcollection_urlafter it credits a business crypto wallet from an on-chain deposit. The payload includescustomer_idwhen the address belongs to a business customer.
New: Crypto API for business wallets
You can manage business crypto wallets through API Services. Create crypto wallets in the Blaaiz dashboard and get their addresses and transactions through API Services. You can swap wallet balances and send on-chain crypto payouts.
- The new Crypto API guide shows the supported wallet, asset, transaction, swap, and payout endpoints.
- New OAuth scopes control access to crypto assets, wallets,
transactions, swaps, and payouts. The
cryptobundle includes all Crypto API scopes. - Crypto swaps and crypto payouts need an
Idempotency-Key. A repeated request with the same key and data returns the first result. - Send each swap or payout amount as a decimal string with no more than 18 decimal places. Swap amount fields also return as decimal strings.
- Crypto payouts send
crypto.payout.processing,crypto.payout.successful, andcrypto.payout.failedto yourpayout_url. The failed event identifies a final failed payout. - Use the webhook log endpoints to inspect deliveries. You can replay an eligible failed crypto payout webhook by its log ID.
- The Payout API no longer supports crypto payouts. Use a Crypto API swap before you create an on-chain crypto payout.
New: add a note to an Interac money request
You can now set a custom note when you initiate an Interac money request. Blaaiz shows this note as the description on the request that the payer approves.
- POST /collection/interac-money-request
now accepts an optional
note. The note is limited to 50 characters. URLs and code-like content are not allowed. - When you omit the
note, Blaaiz uses the standard CAD funding description as before.
New: verify GBP and EUR payee details
You can now verify a payee’s account details before you send a GBP or
EUR payout. Both endpoints need the bank:read scope.
- POST /bank/payee-verification
runs a UK Confirmation-of-Payee check on a GBP account. Send the
sort_code,account_number, and theaccount_namethat you expect. The response returnsmatched,match_confidence_code, andsuggested_account_name. It never returns the real account name. - POST /bank/iban-verification
checks if a EUR
ibanis reachable on SEPA and SEPA Instant. The response returnssepa_reachableandsepa_inst_reachable. This is a reachability check, not a name-match check. - A full match, a close match, and a hard no-match all return
200. For GBP, an account and sort code that the provider rejects as invalid returns400. An invalid request payload returns422.
New: refund a collection to source
You can now refund a collection back to its original sender through the API. Blaaiz refunds the full collection amount only.
- POST /refund starts a
refund. Send the
transaction_id, plus an optionalreasonand an optionalreferenceas an idempotency key. Reusing the samereferenceon the same transaction returns the same refund; reusing it on a different transaction returns400. - GET /refund/ returns a refund by ID.
- Refunds apply to successful EUR and GBP ClearJunction collections that you created through the API for one of your business customers. The refund must start within 7 days of the collection, and each collection can be refunded once. See Refunding a collection.
- New OAuth scopes
refund:createandrefund:read. Both belong to thecollectionsbundle;refund:readalso belongs to theread-onlybundle. - A refund webhook is delivered to
your
collection_urlat initiation (type: refund_initiated,status: processing) and again at the final stage (type: refund,status: successfulorfailed). A declined refund returns afailedwebhook; Blaaiz handles the funds and you do not need to retry. - The transaction responses now include
refund_status. GET /transaction/ also returns a nestedrefundobject when the credential can read refunds (a legacy API key, or an OAuth token withrefund:read).
New: expired collection webhook
Blaaiz now tells you when a collection expires. A collection expires when it is not completed before its expiry time — for example, when a payer does not approve an Interac money request within 48 hours.
- Blaaiz sends a webhook to your
collection_urlwithtransaction_statusset toEXPIREDandmessageset toTransaction Expired. No funds move. See Expired transactions. - List transactions now
accepts
status: EXPIREDso you can find expired collections.
List customers: filters and opt-in pagination
GET /customer now accepts optional exact-match filters and opt-in pagination so you can recover a single customer by identifier or page through large result sets.
- New filters:
email,id_number,registration_number,verification_status(PENDING/PROCESSING/VERIFIED/REJECTED), andtype(individual/business). All are scoped to your business and combine with each other. - Pass
?paginate=trueto receive a paginated envelope (data,links,meta) with 15 items per page. The paginated path returns results newest-first. - Backwards compatible. Omitting
paginatereturns the existing shape unchanged.
New: kyb_scope on business customers — Standard and Minimal KYB
Business customers now carry a kyb_scope field that picks
one of two onboarding paths:
FULL(Standard KYB) — business identity (name, registration number, country of incorporation), beneficial owners summing to 100% ownership, an ID file for each owner, plus a formation document. Eligible for NGN, USD, GBP, and EUR Virtual Bank Accounts.MINIMAL— same business identity as Full, without owners or per-owner ID files, plus a formation document. Eligible for NGN VBAs only.
Who can use Minimal: Minimal is gated by an admin-controlled
allow list — typically Nigerian platforms collecting payments in naira
for their own customers. Allow-listed platforms default to
MINIMAL when they don’t send kyb_scope, and
can pass FULL explicitly when they need non-NGN currencies.
Platforms not on the list default to FULL; sending
MINIMAL returns 422. Contact
support@blaaiz.com if your use
case is genuinely NGN-only.
Upgrading is one-way. UsePOST /customer//upgrade-kyb-scopeto promote a MINIMAL customer to FULL by
adding beneficial owners. There is no downgrade. After the upgrade,
upload owner ID files and call /submit to re-verify under
the Standard checks.
How businesses identify themselves. Every business
customer (Minimal or Full) identifies via
registration_number + incorporation_country.
The id_type and id_number fields are
individual-only — sending them on a business create or update returns
422.
Backwards compatibility. Existing business customers
(created before this release) are tagged kyb_scope=MINIMAL
and have their canonical identity columns backfilled from the legacy
ones. Their NGN VBAs continue to work; the legacy columns stay
populated for read-side compatibility. To enable non-NGN currencies
for an existing business customer, call the upgrade endpoint.
- Business customer KYB — Overview (Two paths section, what we check before /submit, upgrade flow).
- Onboarding a business customer (Minimal KYB onboarding section + Upgrading section).
- POST /customer//upgrade-kyb-scope — new endpoint reference.
Breaking: business-type customers now use a dedicated KYB flow
- You only create
type=individualcustomers — nothing changes. Continue using POST /file/get-presigned-url + POST /customer//files. That flow is unchanged. - You create
type=businesscustomers — yes, you must migrate. The legacyPOST /customer//fileswithid_file=<cert_of_inc>no longer triggers verification for business customers. The file is still stored, but our verification pipeline does not look at it for businesses, and/submitwill return422with a readiness error. - Your existing
VERIFIEDbusiness customers are untouched. They remainVERIFIEDand valid for every operation they were valid for before. You only need to migrate the flow you use to verify new business customers.
- Before (no longer works for business):
POST /customerwithtype=business,id_type=certificate_of_incorporation→ upload via/file/get-presigned-url→POST /customer//fileswithid_file. - Now:
POST /customerwithtype=business+business_name+registration_number+incorporation_country+ (optional)ownersarray (or add owners later viaPUT /customer/) → upload owner ID files viaPOST /customer//owner//file/presigned-urlandPOST /customer//owner//files→ register KYB documents viaPOST /customer//document/presigned-urlandPOST /customer//document→ finalize withPOST /customer//submit. - . Use
registration_number+incorporation_countryas the canonical identifier. Sendingid_typeorid_numberon atype=businesscreate or update returns422. Individuals continue to requireid_type+id_numberas before. - Uniqueness:
registration_numberis now unique within your business perincorporation_country— two of your business customers cannot share the same(registration_number, incorporation_country)pair. The same number across different incorporation countries is fine. - Country fields are explicit and split. A business
customer now carries three ISO alpha-2 country codes, each with a
distinct meaning:
incorporation_country— the legal jurisdiction the company is registered in. Top-level, business-only, required.country— the registered-address country. Top-level, required for both individuals and businesses. For businesses, must equalincorporation_country(a company’s registered office sits in its country of incorporation by company law). The cross-field check is enforced at validation time, including on update — when changing the jurisdiction, send both fields together.operating_country— the operating-address country, on KYC data. Business-only. Required whenever any otheroperating_*field is supplied. Can differ from the other two when the business operates from a different jurisdiction.
zip_codeagainstcountry,operating_zip_codeagainstoperating_country. Same rules acrossPOST /customer,PUT /customer/, andPOST /customer//kyc-data. - Type-specific fields are strictly scoped.
Sending fields that don’t apply to the customer’s
type(for example,operating_*ontype=individual, or business KYB fields on an individual) fails the entire request with422. Send only what applies. - . On
PUT /customer/, sending a property asnullwritesnullto the column. Omit the property to leave it unchanged. Applies to the customer object and to entries inside theownersarray. - The certificate-of-incorporation file goes into the new
KYB document collection (
type=CERTIFICATE_OF_INCORPORATION) instead of through/files.
Readiness floor that /submit enforces for business customers
(each returns 422 with a specific message; same checks
run on initial submit and on re-submit after a REJECTED
verdict):
- Customer-level identity —
business_name,registration_number, and a valid ISOincorporation_countryare all set;countryequalsincorporation_country. - At least one beneficial owner.
- . 99.99% won’t pass.
- Owner emails are unique within the customer (case-insensitive).
- Per-owner ID slot consistency — every owner has
id_document_front;drivers_license/id_card/resident_permitrequireid_document_back;passportmust not have a back image. - Per-owner identity invariants —
date_of_birthis at least 18 years ago,id_expiry_dateis strictly after today, and ISO codes (nationality,country,id_document_country) are valid alpha-2 where set. - At least one KYB document of a formation type:
CERTIFICATE_OF_INCORPORATION,ARTICLES_OF_INCORPORATION,BENEFICIAL_OWNERSHIP_CERTIFICATE,INCORPORATION_DOCUMENTS, orCAC_STATUS_REPORT.
Lock matrix. A child record (owner or document) is
locked if its own status is APPROVED or
PROCESSING, OR the parent customer is in
PROCESSING or VERIFIED. Edits to locked
records return 400. Wait for
customer.status_changed before attempting edits.
Editing a REJECTED owner or document
auto-resets it. Any field change or file replacement on a
previously-rejected owner or document flips its status
back to PENDING and clears its
admin_comments. The corrected record is re-routed
through review on the next /submit. Records that are
APPROVED stay locked and aren’t re-reviewed.
What’s new in the response shape. GET /customer/ now returns:
owners[]— beneficial owners with per-recordstatus(PENDING/PROCESSING/APPROVED/REJECTED) andadmin_comments(array of strings).APPROVEDandPROCESSINGowners are locked from edits.documents[]— KYB document collection with the samestatus+admin_commentsshape and the same lock semantics. Note: this replaces nothing — it is a new field on the customer.- On
customer.status_changedwithnew_status=REJECTEDfor a business customer, render each owner’s and each KYB document’sadmin_commentsentries to your end customer as separate bullets. Rejected items are editable;APPROVEDitems stay locked. Fix and call/submitagain to re-review only the items you changed.
Webhook contract.
customer.status_changed remains the single customer-level event;
you do not need to update your webhook handler. Inspect
old_status and new_status as before. Business
customers introduce one new new_status value:
PROCESSING, fired right after /submit. There are
no per-owner or per-document webhooks — the customer-level
event is the only signal.
Timeline expectations. Individual KYC remains a
minutes-to-2-hours process. Business KYB review typically takes
1–5 business days. Wait for
customer.status_changed; do not raise support tickets within
the standard window.
Currency eligibility. Verified business customers on
kyb_scope=FULL can hold NGN, USD, GBP, and EUR Virtual Bank
Accounts. kyb_scope=MINIMAL customers are NGN-only. For
payout-currency coverage on business recipients, contact support.
Read these before migrating: Business customer KYB overview, Onboarding a business customer (full curl walkthrough + a “Common mistakes” section that calls out the /files trap), Handling KYB rejections, and KYB FAQ.
PHP SDK Now Available
The official framework-agnostic PHP SDK for the Blaaiz Platform API is now available on Packagist. It handles authentication, request signing, and error handling out of the box.
- Install via Composer:
composer require blaaiz/blaaiz-php-sdk - Works with any PHP 8.1+ project — no framework dependency required.
- For Laravel-specific features, the Laravel SDK is also available.
See the SDKs page for all available SDKs.
Customer ID Now Required for All Virtual Bank Accounts
The customer_id field is now required when
creating a Virtual Bank Account for all currencies, including NGN. Previously,
NGN allowed creating accounts without a customer by passing an
account_name instead — this is no longer supported.
customer_idis now a required field in the Create Virtual Bank Account request for all currencies (NGN, GBP, EUR, USD).- The
account_namerequest parameter has been removed. - The customer must have
verification_statusofVERIFIEDbefore a Virtual Bank Account can be created.
Action required: If your integration creates NGN Virtual
Bank Accounts without a customer_id, you must update your
integration to create and verify a customer first.
Back ID Document Support for Customer Verification
The File API and Upload Files endpoint now support back-side identity document uploads for two-sided documents (e.g. driver’s license).
- Added
identity_backas a newfile_categoryoption in the File API presigned upload endpoint. - Added
id_file_backas a new optional parameter in the Upload Files for a Customer endpoint. - Back ID uploads are optional — only needed when the identity document has two sides. Single-sided documents (passport, certificate of incorporation) do not require a back upload.
- The
id_file(front ID) remains the verification trigger. Other files (back ID, liveness check, proof of address) can be uploaded before or alongsideid_filewithout triggering verification. - Rejected customers can now re-upload documents and resubmit for verification without requiring a manual reset.
- Uploads are now blocked while verification is actively in progress to prevent document mutation during review.
Granular OAuth Scopes and Credential Rotation
OAuth credentials now support granular scopes and scope bundles, giving integrators fine-grained control over API access.
- Added documentation for 21 individual OAuth scopes (e.g.
wallet:read,payout:create,webhook:write) and 6 scope bundles (e.g.full-access,read-only,payouts). - Added credential rotation guide — rotate credentials from the dashboard to change scopes or recover from a compromised secret.
- Webhook registration endpoint now returns a
signing_secretin the response. Store this securely to verifyx-blaaiz-signatureheaders. - Legacy API key creation is now disabled. Legacy API key authentication will be removed soon.
OAuth Authentication and Webhook Signing Secret
Blaaiz Platform API authentication is now documented around OAuth client credentials for integrations.
- Added OAuth token acquisition guidance for API access.
- Updated guides and API reference examples to use Bearer tokens instead of legacy API key headers.
- Clarified that webhook signature verification uses a dedicated
webhook
signing_secret, not an API credential secret. - Marked legacy API key usage as temporary and advised all integrators to switch fully to OAuth immediately.
Common Use Cases Guide
We added a new Common use cases guide that walks through the most popular patterns businesses build with the Blaaiz Platform API.
- Cross-border remittances — collect in one currency, pay out in another.
- Marketplace and platform payouts — disburse to sellers across countries.
- Payroll for distributed teams — pay employees in their local currency.
- Virtual accounts for deposit collection — issue dedicated accounts per customer.
- Crypto on/off-ramps — accept stablecoins and settle to fiat.
- B2B invoice and vendor payments — automate cross-border vendor payments.
Each use case includes a flow diagram, step-by-step integration guide, and links to the relevant API endpoints.
Merchant Redirect URL for Collections
The
Initiate Collection
endpoint now accepts an optional redirect_url parameter.
After payment authorization (e.g. 3DS for card collections or open
banking), the customer is automatically redirected to your specified
URL with transaction_id and status query
parameters appended.
- Only HTTPS URLs are accepted (max 2048 characters).
- If no
redirect_urlis provided, the existing default redirect behavior is used. - Query parameters are appended with the correct separator whether your URL already contains a query string or not.
Swap API Reference and Transaction Response Updates
We added documentation for the new
POST /api/external/swap endpoint so businesses can swap
funds between their own wallets.
We also updated the transaction reference to document the latest response shape returned by the API.
Other updates:
- Added the new
SwapAPI reference section and navigation entry. - Documented
type: SWAPas a supported filter on the transaction list endpoint. - Added
swap_detailsto both the list and show transaction response examples and schemas. - Added swap-specific error examples, including validation and access restriction responses.
Virtual Bank Accounts Guide & Payout Documentation Improvements
We added a new Virtual Bank Accounts guide that explains what Virtual Bank Accounts are, how to create them, and the prerequisites for each supported currency (NGN, GBP, EUR, USD).
We also expanded the Creating your first payout guide with currency-specific prerequisites and common error scenarios for NGN, GBP, USD, EUR, and CAD payouts.
Other updates:
- Updated the Virtual Bank Account creation response message to reflect the new “initiated” status wording.
- Added new Virtual Bank Account validation error examples to the Payout API reference.
- Added request examples for every supported currency and payout method (NGN, GBP, USD ACH, USD Wire, EUR, CAD Interac, and Crypto) to the Payout API reference.
New Blaaiz Platform API Documentation 🎉
Migrated to the new docs platform. It now features: a more intuitive navigation and a better search experience.
- A more intuitive navigation and a better search experience.
- An interactive playground for testing API endpoints.
- Refined API Reference layout and examples.