Getting Started
This guide provides an introduction to getting started with the Harbor API, including how to authenticate requests, create customers, link blockchain addresses or bank accounts, and make API calls with the required headers and parameters.
Role Definitions
- Harbor: Refers to us in this document.
- Application: Our integration partners.
- Customer: Typically the customers of an Application.
Due to compliance requirements, Harbor requires Applications to provide Customer KYC (Know Your Customer) information during integration. Alternatively, we provide a direct KYC link that enables customers to submit their information seamlessly.
Once a Customer submits their KYC data, the Application can refer to the following status flow diagram to understand the current review status. For a detailed explanation of each status, please refer to Status .

Customer KYC status change diagram
Step 1: Contact us to get Sandbox/Production information
To get started with OwlPay Harbor, please contact us to obtain sandbox and production access. We'll first provide you with sandbox credentials and an API_KEY for testing in your environment. Once you've completed the integration, we'll issue your PRODUCTION API_KEY, allowing you to go live 🎊.
Keep your private key safe
If you lose your PRODUCTION API_KEY, contact our customer service immediately. Ensure that your API_KEY is stored securely and never shared or exposed to insecure environments to prevent potential leaks.
Step 2: Register Your First Customer
You are now ready to start using Harbor’s core APIs.
The first step is to create a customer object that represents a user in your system.
When making this request, you need to set specific headers as shown in the example below. Most importantly, you must include the X-API-KEY header to authorize API access.
Agreement Link
- The Customer must agree to Harbor’s Agreements before we can proceed with the KYC/AML verification process.
curl --location --request POST 'https://harbor-sandbox.owlpay.com/api/v1/customers' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'X-Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
"type": "individual",
"first_name": "John",
"middle_name": "Michael",
"last_name": "Doe",
"email": "[email protected]",
"phone_country_code": "US",
"phone_number": "555-555-1234",
"birth_date": "1988-04-15",
"description": "A freelance writer who loves exploring national parks."
}'
The endpoint will return a response as shown below.
{
"data": {
"uuid": "{{customer_uuid}}",
"status": "inactive",
"type": "individual",
"first_name": "John",
"middle_name": "Michael",
"last_name": "Doe",
"email": "[email protected]",
"phone_country_code": "US",
"phone_number": "555-555-1234",
"birth_date": "1988-04-15",
"kyc_link": "https://harbor.owlpay.com/kyc_link",
"agreement_link": "https://harbor.owlpay.com/agreement_link",
"has_signed_agreement": false,
"description": "A freelance writer who loves exploring national parks.",
"created_at": "2025-02-11T06:35:50+00:00",
"updated_at": "2025-02-11T06:35:50+00:00"
}
}
Note: You will receive a customer ID (cus_xxx). If you need to add bank accounts or other related information, this ID is required to make requests to the corresponding endpoints.
Step 3: Register the customer’s bank account by customer uuid (For off-ramping)
Confirm the status of the Customer
When the Customer status is Verified, you can send Register the customer’s bank account or Register the customer’s crypto address.
curl --location --request POST 'https://harbor-sandbox.owlpay.com/api/v1/customers/{{customer_uuid}}/bank_accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'X-Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
"account_number": "124567890",
"routing_number": "021000021",
"bank_name": "Chase Bank",
"bank_address": "270 Park Avenue, New York, NY 10017",
"account_holder_name": "John Michael Doe"
}'
The endpoint will return a response as shown below.
{
"data": {
"uuid": "{{bank_uuid}}",
"customer_uuid": "{{customer_uuid}}",
"account_number": "124567890",
"routing_number": "021000021",
"bank_name": "Chase Bank",
"bank_address": "270 Park Avenue, New York, NY 10017",
"account_holder_name": "John Michael Doe",
"updated_at": "2025-02-11T06:47:49+00:00",
"created_at": "2025-02-11T06:47:49+00:00"
}
}
Step 4: Register the customer’s crypto address by customer uuid (For on-ramping)
curl --location --request POST 'https://harbor-sandbox.owlpay.com/api/v1/customers/{{customer_uuid}}/crypto_addresses' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'X-Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
"chain": "ethereum",
"address": "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db"
}'
The endpoint will return a response as shown below.
{
"data": {
"uuid": "{{crypto_uuid}}",
"customer_uuid": "{{customer_uuid}}",
"chain": "ethereum",
"asset": "USDC",
"address": "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db",
"status": null,
"updated_at": "2025-02-11T06:28:49+00:00",
"created_at": "2025-02-11T06:28:49+00:00"
}
}
Step 5: Move your first dollar (do an on/off ramp transfer)
The following is a quick reference to the on-ramp request and response. For detailed parameters, please see Transfer.
curl --location 'https://harbor-sandbox.owlpay.com/api/v1/transfer' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'X-Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
"commission": {
"percentage": "0.01",
"amount": "1.00",
},
"source": {
"asset": "USD",
"amount": "100.00",
},
"destination": {
"asset": "USDC",
"chain": "ethereum",
"address": "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db"
},
"application_transfer_uuid": "{{YOUR_APPLICATION_TRANSFER_UUID}}"
}'
Note: If you want to use a specific customer crypto address, include the customer_crypto_address_id field, and omit asset, chain, and address. Otherwise, you can specify the asset, blockchain network, and recipient address directly in the destination field.
curl --location 'https://harbor-sandbox.owlpay.com/api/v1/transfer' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'X-Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
"commission": {
"percentage": "0.01",
"amount": "1.00",
},
"source": {
"asset": "USD",
"amount": "100.00",
},
"destination": {
"asset": "USDC",
"customer_crypto_address_id": "{{CUSTOMER_CRYPTO_ADDRESS_ID}}", // Optional, if you want to use a pre-created customer crypto address, you can provide the id here (If you input both, destination.address will be ignored)
},
"application_transfer_uuid": "{{YOUR_APPLICATION_TRANSFER_UUID}}"
}'
The endpoint will return a response as shown below.
{
"status": "pending_customer_transfer_start",
"source": {
"asset": "USD",
"amount": "100.00",
},
"destination": {
"asset": "USDC",
"payment_rail": "ethereum",
"address": "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db",
"amount": "98.00",
},
"application_transfer_uuid": "{{YOUR_APPLICATION_TRANSFER_UUID}}",
"transfer_instructions": {
"account_number": "123456789012",
"routing_number": "021000021",
"bank_name": "Test Bank USA",
"bank_address": "123 Test Street, New York, NY 10001, USA",
"account_holder_name": "John Doe",
"narrative": "123456789012"
},
"commission": {
"percentage": "0.01",
"amount": "1.00",
},
"receipt": {
"initial_amount": "100.00",
"commission_fee": "2.00",
"harbor_fee": "0.5",
"final_amount": "97.50",
"transaction_hash": null, // This field will be filled if the transfer status is completed, otherwise it will be empty
},
"created_at": "2025-02-07T13:05:32+00:00",
"updated_at": "2025-02-07T13:05:32+00:00"
}
Off-ramp (Sell USDC example)
curl --location 'https://harbor-sandbox.owlpay.com/api/v1/transfer' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'X-Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
"commission": {
"percentage": "0.01",
"amount": "1.00",
},
"source": {
"chain": "ethereum",
"asset": "USDC",
"amount": "1000.00",
},
"destination": {
"asset": "USD",
"account_number": "123456789012",
"routing_number": "021000021",
"bank_name": "Test Bank USA",
"bank_address": "123 Test Street, New York, NY 10001, USA",
"account_holder_name": "John Doe"
},
"application_transfer_uuid": "{{YOUR_APPLICATION_TRANSFER_UUID}}"
}'
Note: If you want to use a specific customer bank account, include the customer_bank_account_id field, and omit bank information (account_number/routing_number/bank_name/bank_address/account_holder_name).
curl --location 'https://harbor-sandbox.owlpay.com/api/v1/transfer' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-API-KEY: {{API_KEY}}' \
--header 'X-Idempotency-Key: {{Idempotency-Key}}' \
--data-raw '{
"commission": {
"percentage": "0.01",
"amount": "1.00",
},
"source": {
"chain": "ethereum",
"asset": "USDC",
"amount": "1000.00",
},
"destination": {
"asset": "USD",
"customer_bank_account_id": "{{CUSTOMER_BANK_ACCOUNT_ID}}", // Optional, if you want to use a specific customer bank account, you can provide the id here (If you input both, customer_bank_account_id will be used first)
},
"application_transfer_uuid": "{{YOUR_APPLICATION_TRANSFER_UUID}}"
}'
The endpoint will return a response as shown below.
{
"status": "pending_customer_transfer_start",
"source": {
"chain": "ethereum",
"asset": "USDC",
"amount": "1000.00",
},
"destination": {
"asset": "USD",
"account_number": "123456789012",
"routing_number": "021000021",
"bank_name": "Test Bank USA",
"bank_address": "123 Test Street, New York, NY 10001, USA",
"account_holder_name": "John Doe",
"amount": "980.00",
},
"application_transfer_uuid": "{{YOUR_APPLICATION_TRANSFER_UUID}}",
"transfer_instructions": {
"chain": "ethereum",
"address": "0x6990E7E90ab50C12111f99b84183D3fE298Bb3e4"
},
"commission": {
"percentage": "0.01",
"amount": "1.00",
},
"receipt": {
"initial_amount": "1000.00",
"commission_fee": "20.00",
"harbor_fee": "5.00",
"final_amount": "975.00",
"tracking_number": null, // This field will be filled if the transfer status is `bank_in_process`
},
"created_at": "2025-02-07T13:05:32+00:00",
"updated_at": "2025-02-07T13:05:32+00:00"
}
Congratulations! You have the on/off-ramp deposit and withdrawal information. You can execute the payment according to the API response, and then your destination will receive the corresponding assets.
Updated 10 days ago