API Reference
Overview
The BaaSReferralGateway exposes three endpoints. All paths are appended to the Base URL provided by Green Dot for the target environment.
| Endpoint | Method | Path | Auth Required |
|---|---|---|---|
| Enrollment | POST | /programs/{PROGRAM_CODE}/enrollment | Yes (ENROLLMENT role) |
| Order Card | PUT | /programs/{PROGRAM_CODE}/lifecycleEvent | Yes (ORDERCARD role) |
| Health Check | GET | /healthcheck | No |
Client timeout: Set your HTTP client timeout to at least 35 seconds on all requests.
Enrollment API
Creates a Green Dot customer account, issues a virtual card, and runs KYC/OFAC - all in a single synchronous call. Physical card issuance is a separate, subsequent call.
Endpoint
POST {BASE_URL}/programs/{PROGRAM_CODE}/enrollmentRequired role: ENROLLMENT
Required Flags
requestPhysicalCardFlag- must befalse. Physical card ordering is a separate call.executeKycFlag- must betrue. KYC is always performed.
PII Encryption
All customer PII is sent encrypted inside user.encryptedUserData.data. Non-PII control fields are sent in plaintext.
Green Dot provides an EC public key per environment. The partner:
- Builds the PII JSON payload (see PII Payload below).
- Serializes it as a string.
- Encrypts it using Green Dot's EC public key (EC_v1 / ECIES).
- Base64-encodes the result and places it in
encryptedUserData.data. - Provides the ephemeral public key and public key hash generated during encryption.
Request Body
{
"user": {
"encryptedUserData": {
"version": "EC_v1",
"ephemeralPublicKey": "{string}",
"publicKeyHash": "{string}",
"data": "{base64-encrypted-pii-payload}"
}
},
"account": {
"productCode": "{PRODUCT_CODE}",
"productMaterialType": "{PRODUCT_MATERIAL_TYPE_VIRTUAL}",
"currency": "USD",
"termsAcceptances": [
{
"termsIdentifier": "{TERMS_IDENTIFIER}",
"termsAcceptanceFlag": true,
"termsAcceptanceDateTime": "2024-04-15T10:30:00.000Z"
}
],
"fraudData": {
"IpAddress": "{customer_ip_address}"
}
},
"requestPhysicalCardFlag": false,
"executeKycFlag": true
}PII Payload
Serialize this JSON object as a string, then encrypt it using Green Dot's EC public key before placing the result in encryptedUserData.data.
{
"profileData": {
"firstName": "John",
"middleName": "Smith",
"lastName": "Robert",
"addresses": [
{
"type": "home",
"isDefault": true,
"addressLine1": "15777 Foothill Blvd",
"addressLine2": "SUITE 560",
"city": "Pasadena",
"state": "CA",
"zipCode": "91107",
"isVerified": true
}
]
},
"identifyingData": {
"ssn": "XXXXXXXXX",
"ssnSuffix": "",
"dateOfBirth": "YYYY-MM-DD"
},
"email": {
"emailAddress": "[email protected]",
"isDefault": true,
"isVerified": true
},
"phoneNumbers": [
{
"number": "XXXXXXXXXX",
"type": "mobile",
"isDefault": true,
"isVerified": true
}
]
}PII Field Rules
Name Fields
| Field | Required | Rules |
|---|---|---|
firstName | Yes | 1–35 characters. See Appendix A for allowed characters. |
middleName | No | Max 100 characters. See Appendix A. |
lastName | Yes | 2–35 characters. See Appendix A. |
Address Fields
| Field | Required | Rules |
|---|---|---|
addresses.type | Yes | Must be "home". |
addresses.isDefault | Yes | Must be true. Only one default address allowed. Home address must be the default. |
addressLine1 | Yes | 2–40 characters. Must not be a PO Box. Must not include addressLine2 content in this field. See Appendix A. |
addressLine2 | No | Max 40 characters. Also checked for PO Box patterns. See Appendix A. |
city | Yes | Max 25 characters. Also checked for PO Box patterns. See Appendix A. |
state | Yes | Two-character uppercase code. See Appendix A — State Codes for accepted values (50 states + DC + territories + military APO/FPO). |
zipCode | Yes | 5-digit (XXXXX) or ZIP+4 (XXXXX-XXXX). Must correspond to the state provided or a bordering state — mismatch returns 1042/31006. If state is omitted, it is inferred from the ZIP. |
Identity Fields
| Field | Required | Rules |
|---|---|---|
ssn | Yes | Full 9-digit Social Security number. |
ssnSuffix | Yes | Reserved. Must always be submitted as an empty string "". Use ssn for the full SSN. |
dateOfBirth | Yes | Format: YYYY-MM-DD. Must be between 1901-01-01 and today. |
Contact Fields
| Field | Required | Rules |
|---|---|---|
emailAddress | Yes | Max 255 characters. In PROD: the + character in the username portion is not allowed. In PIE/QA/DEV it is accepted. |
phone.number | Yes | Exactly 10 digits, no country code prefix. Only one phone number may be submitted. |
phone.type | Yes | Must be "mobile". Any non-mobile phone type will be declined. |
isVerified | No | Set true if your platform has verified the contact channel (e.g., via OTP). |
Terms Acceptances
The termsAcceptances array must include all terms required for your product. Green Dot confirms the exact required list during product setup.
Known Terms Identifier Values
termsIdentifier | Description | Typical termsAcceptanceFlag |
|---|---|---|
daa | Deposit Account Agreement | true |
privPlcy | Privacy Policy | true |
eca | Electronic Communications Agreement | true |
TcpaPromo | TCPA Promotional Messaging Express Written Consent | true or false |
TcpaInfo | TCPA Informational Messaging Express Consent | true |
ecbsv | Electronic Consent Based Social Security Number Verification | true |
The exact required terms for your product code will be confirmed by Green Dot during product setup.
termsAcceptanceDateTime Format
termsAcceptanceDateTime FormatMust be ISO 8601 UTC with fractional seconds ending in Z. Accepted formats:
yyyy-MM-ddTHH:mm:ssZ
yyyy-MM-ddTHH:mm:ss.SZ
yyyy-MM-ddTHH:mm:ss.SSZ
yyyy-MM-ddTHH:mm:ss.SSSZ
Valid examples:
"2024-04-15T10:30:00.000Z"✅"2024-04-15T10:30:00.0Z"✅
Invalid examples:
"2024-04-15T10:30:00"❌ - missing Z and fractional seconds"2024-04-15T10:30:00.000"❌ - missing Z
The datetime must be within ±720 hours of the server's current time. Outside that window → error 620/0. Unparseable format → error 720/0.
Fraud Data
| Field | Required | Description |
|---|---|---|
account.fraudData.IpAddress | Yes | The customer's originating IP address as seen by the partner's server. |
Green Dot will advise if additional fraud fields are required during onboarding.
Enrollment Success Response (HTTP 201)
{
"responseDetails": [
{
"code": 0,
"subCode": 0,
"description": "API operation was successful.",
"url": "http://tbd"
}
],
"account": {
"accountIdentifier": "f096a92e-a7e9-4d66-8fc6-c3ee99227d59",
"accountReferenceNumber": "ACCJ2530733",
"status": "normal",
"accountStatusChangedDateTime": "2024-07-03T03:08:36.933Z",
"statusReasons": ["healthy"],
"directDepositInformation": {
"accountNumber": "15101332927074",
"routingNumber": "124303162"
},
"purses": [
{
"purseIdentifier": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"purseType": "primary",
"availableBalance": 0.0000,
"ledgerBalance": 0.0000,
"status": "active"
}
],
"accountHolders": [
{
"user": {
"userIdentifier": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "active",
"isPrimaryAccountHolder": true,
"kycStateData": {
"ofacStatus": "passed",
"kycStatus": "passed",
"kycPendingGate": "healthy"
}
},
"accountHolderIdentifier": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"paymentInstruments": [
{
"paymentInstrumentIdentifier": "9b0dbe09-6e98-4488-bde7-52828aa4b324",
"paymentInstrumentType": "virtual",
"status": "activated",
"isPinSet": false,
"last4Pan": "****",
"encryptedPrivatePaymentInstrumentData": {
"version": "EC_v1",
"ephemeralPublicKey": "string",
"publicKeyHash": "string",
"data": "string"
}
}
]
}
]
}
}Fields to Persist
You must store these values from the enrollment response - both are required for the Order Card call:
| Field | Path in Response | Use |
|---|---|---|
accountIdentifier | account.accountIdentifier | Required for Order Card API |
paymentInstrumentIdentifier | account.accountHolders[0].paymentInstruments[0].paymentInstrumentIdentifier | Required for Order Card API |
encryptedPrivatePaymentInstrumentData | account.accountHolders[0].paymentInstruments[0].encryptedPrivatePaymentInstrumentData | Decrypt with your own private key to obtain full virtual card details (PAN, CVV, expiry) for display to the customer |
accountNumber + routingNumber | account.directDepositInformation | Submit to IRS as the refund destination |
Idempotency
The Enrollment API uses X-GD-RequestId as an idempotency key. If you re-submit an enrollment request with the same X-GD-RequestId as a previous KYC/OFAC failure, the response kycStateData fields will return zeros rather than the original failure values. The responseDetails code and subcode will still reflect the original result.
Important: Always generate a fresh UUID for new enrollment attempts. Reusing an X-GD-RequestId from a failed request is not a retry mechanism.
Enrollment Error Codes
Errors are returned in responseDetails[0] as code / subCode. Check both the HTTP status and the code field - some non-zero codes are returned with HTTP 200 or HTTP 201.
Warning: Do not treat HTTP 201 as unconditional success. A
201response with a non-zerocodeindicates a KYC/OFAC decline. Always inspectresponseDetails[0].code.
KYC / Identity Verification Results
| HTTP | code | subCode | Meaning | Partner Action |
|---|---|---|---|---|
| 201 | 0 | 0 | Success | Proceed — account created |
| 201 | 2 | 11 | KYC hard decline — no cure path | Do not retry. Enrollment is permanently declined. Green Dot handles customer communication. |
| 201 | 2 | 31 | OFAC hard match — declined | Do not retry. Enrollment is permanently declined. |
| 201 | 2 | 33 | KYC + OFAC both failed — no cure path | Do not retry. Enrollment is permanently declined. |
For tax-season referral partner products, KYC and OFAC failures result in a permanent hard decline. There is no identity verification step-up, document upload, or cure action available through this API.
Full Error Code Catalog
| HTTP | code | subCode | Description |
|---|---|---|---|
| 201 | 0 | 0 | Success |
| 400 | 1 | 10 | KYC failed — curable (customer may submit ID documents) |
| 400 | 1 | 34 | KYC and OFAC failed — KYC curable |
| 201 | 2 | 11 | KYC hard decline — no cure path |
| 201 | 2 | 30 | Address is not a valid U.S. address |
| 201 | 2 | 31 | OFAC hard match — declined |
| 201 | 2 | 32 | OFAC secondary review required |
| 201 | 2 | 33 | KYC and OFAC — hard decline |
| 201 | 2 | 40 | Customer must be 18 or older |
| 200 | 2 | 55 | Required terms not accepted or missing from request |
| 200 | 2 | 60 | Active account limit reached for this SSN |
| 200 | 2 | 61 | Lifetime activated account limit reached |
| 200 | 2 | 62 | Enrollment attempt lifetime limit |
| 200 | 2 | 63 | Active account limit reached (phone limit) |
| 200 | 2 | 64 | Account holder limit |
| 200 | 2 | 66 | Phone lifetime limit |
| 200 | 2 | 67 | 7-day account open limit reached |
| 200 | 2 | 68 | 30-day account open limit reached |
| 200 | 2 | 69 | Email exceeded |
| 400 | 43 | 12 | Invalid productMaterialType value |
| 400 | 56 | 5 | Product not available in this region |
| 400 | 50 | 0 | Encrypted data block could not be decrypted |
| 400 | 100 | 0 | Request body is malformed JSON |
| 400 | 101 | 0 | Invalid request parameters (executeKycFlag must be true, requestPhysicalCardFlag must be false, missing sections, etc.) |
| 400 | 101 | 191 | Fraud decline — Iocation check failed |
| 400 | 101 | 192 | Duplicate email — account already exists with this email. The existing accountIdentifier and paymentInstrumentIdentifier are returned in the response body. |
| 400 | 200 | 0 | Missing required field |
| 400 | 350 | 0 | Invalid format (invalid base64 in encrypted fields, phone number format, etc.) |
| 400 | 400 | 501 | firstName exceeds 35 characters |
| 400 | 400 | 502 | lastName < 2 or > 35 characters |
| 400 | 400 | 504 | city exceeds 25 characters |
| 400 | 400 | 505 | addressLine1 < 2 or > 40 characters |
| 400 | 400 | 506 | addressLine2 exceeds 40 characters |
| 400 | 500 | 0 | Encryption or decryption error |
| 400 | 600 | 0 | Invalid encryption version |
| 400 | 602 | 0 | Program not fully configured on Green Dot side |
| 400 | 603 | 0 | Only one mobile phone number is allowed |
| 400 | 620 | 0 | termsAcceptanceDateTime is outside the ±720-hour window |
| 400 | 630 | 0 | Cannot pass both ssnSuffix and ssn — use ssn only; ssnSuffix must be empty string |
| 400 | 640 | 501 | Invalid characters in firstName |
| 400 | 640 | 502 | Invalid characters in lastName |
| 400 | 640 | 503 | Invalid characters in middleName |
| 400 | 640 | 504 | Invalid characters in city |
| 400 | 640 | 505 | Invalid characters in addressLine1 |
| 400 | 640 | 506 | Invalid characters in addressLine2 |
| 400 | 650 | 0 | Invalid ISO currency code |
| 400 | 650 | 430 | Currency not supported for this program |
| 400 | 700 | 0 | dateOfBirth not in YYYY-MM-DD format |
| 400 | 720 | 0 | termsAcceptanceDateTime is not a valid ISO 8601 UTC datetime |
| 400 | 750 | 0 | Invalid email format |
| 400 | 760 | 0 | Invalid SSN |
| 400 | 1020 | 0 | Duplicate address types in the addresses array |
| 400 | 1040 | 0 | More than one address set as isDefault: true |
| 400 | 1041 | 0 | Home address must be the default address |
| 400 | 1042 | 0 | Home address is missing — a type: "home" address is required |
| 400 | 1042 | 31000 | Country code missing |
| 400 | 1042 | 31001 | Country code invalid format (must be exactly 3 uppercase ASCII letters) |
| 400 | 1042 | 31003 | State code is not in the accepted list |
| 400 | 1042 | 31004 | ZIP code missing |
| 400 | 1042 | 31005 | ZIP code invalid format |
| 400 | 1042 | 31006 | ZIP code does not match the provided state |
| 400 | 1042 | 31007 | PO Box detected in address fields |
| 400 | 1042 | 31008 | ZIP code prefix is not recognized |
| 400 | 1042 | 31009 | ZIP code maps to multiple states — include the state field to resolve ambiguity |
| 503 | 600 | 0 | Downstream service unavailable |
Order Card API
Orders a physical EMV card for a customer whose account was created via the Enrollment API. Physical card issuance is intentionally decoupled from enrollment — the partner calls this API when their business trigger occurs.
Endpoint
PUT {BASE_URL}/programs/{PROGRAM_CODE}/lifecycleEventRequired role: ORDERCARD
When to Call
There is no minimum or maximum time window between enrollment and Order Card. For tax referral partners, this call is typically made when the IRS accepts the customer's tax filing - which may be days or weeks after enrollment.
10-day dedup window: Once an Order Card call succeeds for an account, a second call for that same account within 10 days is rejected with code 4 / subCode 308. There is no maximum deadline - the call is accepted whenever it arrives.
Request Body
{
"accountIdentifier": "{accountIdentifier from enrollment response}",
"paymentInstrumentIdentifier": "{paymentInstrumentIdentifier from enrollment response}",
"lifeCycleEventType": "replacement",
"productMaterialType": "{PRODUCT_MATERIAL_TYPE_EMV}",
"replaceReason": "initialPhysicalCard"
}Request Fields
| Field | Required | Rules |
|---|---|---|
accountIdentifier | Yes | The account.accountIdentifier returned by the Enrollment API. |
paymentInstrumentIdentifier | Yes | The paymentInstruments[0].paymentInstrumentIdentifier returned by the Enrollment API. Must be the current virtual card identifier — if the card was reissued after enrollment, use the updated identifier. A stale identifier passes gateway validation but is rejected by the platform with code 4 / subCode 303. |
lifeCycleEventType | Yes | Must be exactly "replacement" (case-insensitive). Any other value is rejected. |
productMaterialType | Yes | The EMV product material type — use {PRODUCT_MATERIAL_TYPE_EMV} provided by Green Dot during onboarding. |
replaceReason | Yes | Must be exactly "initialPhysicalCard" (case-insensitive). Any other value is rejected. initialPhysicalCard can only be called once per account. |
Success Response (HTTP 200)
{
"responseDetails": [
{
"code": 0,
"subCode": 0,
"description": "API operation was successful.",
"url": "http://tbd"
}
]
}No additional fields are returned on success. Green Dot does not provide an order ID or card tracking token in this response.
Order Card Error Codes
Important: All Order Card errors - including account and card state rejections - are returned with HTTP 200 and a non-zero
code. Do not treat an HTTP 200 response as unconditional success - always checkresponseDetails[0].code.
| HTTP | code | subCode | Description |
|---|---|---|---|
| 200 | 0 | 0 | Success — physical card ordered |
| 200 | 4 | 105 | Account is closed |
| 200 | 4 | 106 | Account is locked |
| 200 | 4 | 300 | Card reported lost or stolen |
| 200 | 4 | 303 | paymentInstrumentIdentifier is stale - the virtual card was reissued after enrollment; retrieve and use the current identifier |
| 200 | 4 | 308 | Duplicate request - an Order Card call for this account already succeeded within the last 10 days |
| 200 | 4 | 310 | A physical card already exists on this account - initialPhysicalCard can only be called once per account |
| 200 | 4 | 323 | Mailing address on file is invalid - card cannot be shipped |
| 400 | 101 | 0 | Invalid request - check that lifeCycleEventType is "replacement", replaceReason is "initialPhysicalCard", and all required fields are present |
| 503 | 600 | 0 | Downstream service unavailable - retry with backoff |
Health Check
Verifies connectivity to the BaaSReferralGateway and its downstream services. Use this endpoint before running integration tests.
Endpoint
GET {BASE_URL}/healthcheckNo Bearer token required. X-GD-RequestId is still required. Use X-Program-Code in PROD to route the probe to the correct program's downstream services.
Response (HTTP 200 — healthy)
{
"responseDescription": "Health Check Completed.",
"status": "OK",
"totalTime": "1873.0287",
"healthCheck": [
{ "serviceName": "Service1", "status": "OK", "totalTime": "650.5256" },
{ "serviceName": "Service2", "status": "OK", "totalTime": "593.6144" },
{ "serviceName": "Service3", "status": "OK", "totalTime": "532.6803" },
{ "serviceName": "Service4", "status": "OK", "totalTime": "96.1526" }
],
"responseDetails": [
{ "code": 0, "subCode": 0, "description": "Success", "url": "http://tbd" }
]
}A degraded status on any individual service indicates a partial outage affecting that component only.
Error Handling Recommendations
Always Check responseDetails[0].code
responseDetails[0].codeThe HTTP status code alone is not sufficient to determine success or failure:
- Some enrollment failures return
HTTP 201with a non-zerocode(KYC/OFAC declines). - All Order Card errors return
HTTP 200with a non-zerocode. - Always read
responseDetails[0].codeandresponseDetails[0].subCodeon every response.
Retry Strategy
| Scenario | Recommended Action |
|---|---|
HTTP 503 / code 600 | Retry with exponential backoff. Downstream service temporarily unavailable. |
HTTP 400 | Do not retry without fixing the request. These are validation errors. |
HTTP 401 | Token expired or invalid. Refresh token and retry once. |
HTTP 403 | Missing role claim. Contact Green Dot - do not retry. |
KYC/OFAC hard decline (code 2, subCodes 11, 31, 33) | Do not retry. Permanent decline. |
Duplicate email (code 101, subCode 192) | Do not retry with the same email. The existing account identifiers are returned in the response. |
Partner Implementation Checklist
- Receive Azure AD
clientIdandclientSecretfrom Green Dot for each environment - Implement OAuth 2.0 client credentials token acquisition with caching and auto-refresh
- Receive Green Dot EC public key per environment
- Implement EC_v1 PII encryption using GD public key
- Generate a unique
X-GD-RequestId(UUID) on every request - Build the Enrollment request with all required fields and correct
termsAcceptances - Persist
accountIdentifierandpaymentInstrumentIdentifierper customer after enrollment - Confirm terms identifiers with Green Dot and validate the datetime format
- Implement the Order Card call with the business trigger condition
- Handle HTTP 200 responses with non-zero
code- do not treat as success - Implement retry and error handling for
400and503responses - Verify connectivity using the
/healthcheckendpoint before testing - Set HTTP client timeout to at least 35 seconds
Appendix A - Valid Characters and Address Rules
Name Fields (firstName, middleName, lastName)
firstName, middleName, lastName)Unicode is not allowed. Accepted values are ASCII range 32–126, excluding:
33–38, 40–43, 47, 58–64, 91–96, 123–126
Street and City Fields (addressLine1, addressLine2, city)
addressLine1, addressLine2, city)Unicode is not allowed. Accepted values are ASCII range 32–126 and 192–255, excluding:
33–34, 36–37, 42–43, 58–64, 91–96, 123–126, 215, 217–220, 247
PO Box Rejection
PO Box detection applies to addressLine1, addressLine2, and city. A broad pattern of common variants is rejected:
PO Box, P.O. Box, POB, POBOX, Post Office Box, Box NNN, General Delivery, Drawer, Caller, Lockbox, PMB, and deliberate obfuscation variants (e.g., p0 box, po-box).
Allowed exceptions (legitimate addresses that match PO Box patterns): Army Post Office (APO), Fleet Post Office (FPO), Diplomatic Post Offices, PSC N Box N, RR N Box N, and street names such as Box Hill, Box Canyon, Box Street, Post Oak, and Postal Road.
State Codes
State must be exactly 2 uppercase ASCII characters. Accepted values:
50 U.S. States + DC:
AL AK AZ AR CA CO CT DE DC FL GA HI ID IL IN IA KS KY LA ME
MD MA MI MN MS MO MT NE NV NH NJ NM NY NC ND OH OK OR PA RI
SC SD TN TX UT VT VA WA WV WI WY
U.S. Territories (also accepted):
PR (Puerto Rico)
VI (U.S. Virgin Islands)
GU (Guam)
AS (American Samoa)
MP (Northern Mariana Islands)
Military APO/FPO codes (also accepted):
AA (Americas)
AE (Europe / Middle East / Africa)
AP (Pacific)
Canadian province codes (AB, BC, ON, etc.) and any other two-letter code not listed above are rejected with error 1042/31003.
ZIP Code Rules
- Format:
XXXXX(5 digits) orXXXXX-XXXX(ZIP+4). Both are accepted. - The ZIP must correspond to the
statefield. A mismatch with the state (or its bordering states) returns1042/31006. - If
stateis omitted, the state is inferred from the ZIP prefix. If the prefix maps to multiple states, error1042/31009is returned - include thestatefield to resolve. - Unrecognized ZIP prefixes return
1042/31008.
Updated 6 days ago
