nestJS with typeorm : #Expose not work when entity nested - nested

In my project,
there are two entities; Profile and Project.
Entity Project has field "collaborators", which is array of Profile. -> code
Entity Profile has two #Expose fields, "nickname" and "id", which is well-shown when I call GET Profile API.
-> code
-> see result of dev.collact.io/api/profiles/8.
{
"createdDt": "2021-10-05T14:51:29.312Z",
"updatedDt": "2021-10-05T14:51:29.312Z",
"deletedDt": null,
"photo": "https://collact-dev.s3.ap-northeast-2.amazonaws.com/profiles/oj2UBVFXCTnZ9z9mmy8UtU-59FD9F11-1812-4758-85B7-4347A4CE0FEF.png",
"contact": null,
"intro": null,
"detail": null,
"email": null,
"phone": null,
"projects": [],
"nickname": "Tester",
"id": 8
}
However, when I call GET Project API, the exposed fields, "nickname" and "id" does not come up inside "collaborators".
-> see result of dev.collact.io/api/projects/72.
{
"createdDt": "2021-12-20T18:14:22.277Z",
"updatedDt": "2021-12-20T18:14:22.277Z",
"deletedDt": null,
"id": 72,
"photos": [
{
"createdDt": "2021-12-20T18:14:22.321Z",
"updatedDt": "2021-12-20T18:14:22.321Z",
"deletedDt": null,
"id": 26,
"photo": "https://collact-dev.s3.ap-northeast-2.amazonaws.com/projects/cWk3fQEoperPxAS6T1QV5K.png"
}
],
"collaborators": [
{
"createdDt": "2021-10-03T14:53:20.165Z",
"updatedDt": "2021-12-09T13:26:11.870Z",
"deletedDt": null,
"photo": "https://collact-dev.s3.ap-northeast-2.amazonaws.com/profiles/oj2UBVFXCTnZ9z9mmy8UtU-59FD9F11-1812-4758-85B7-4347A4CE0FEF.png",
"contact": "ㅆZz",
"intro": "Zz",
"detail": "Asdfasdf",
"email": null,
"phone": null
}
],
"areas": [
{
"createdDt": "2021-07-12T13:28:12.063Z",
"updatedDt": "2021-07-12T13:28:12.063Z",
"deletedDt": null,
"id": 1,
"area": "drawing"
},
{
"createdDt": "2021-07-12T13:28:12.063Z",
"updatedDt": "2021-07-12T13:28:12.063Z",
"deletedDt": null,
"id": 2,
"area": "design"
}
],
"title": "title",
"detail": ""
}
I already tried 2 solutions but does not work as I want.
First, I tried to add #Type(() => Profile) to "collaborators" in Project entity but had no difference.
Second, I thought join only worked until collaborators, so needed to join until collaborators.user like below.
findOne(id: string): Promise<Project> {
return this.projectsRepository.findOne(id, {
relations: ['collaborators', 'collaborators.user', 'areas', 'photos'],
});
}
However, this time, "nickname" and "id" does not come up for collaborators. Rather, nested user object as a whole, comes up.
{
"createdDt": "2021-10-03T11:49:51.052Z",
"updatedDt": "2021-10-03T11:49:51.052Z",
"deletedDt": null,
"id": 4,
"title": "title2",
"detail": "",
"collaborators": [
{
"createdDt": "2021-10-03T11:46:20.347Z",
"updatedDt": "2021-10-03T11:46:20.347Z",
"deletedDt": null,
"photo": null,
"contact": null,
"intro": null,
"detail": null,
"email": null,
"phone": null,
"user": {
"createdDt": "2021-10-03T11:46:20.347Z",
"updatedDt": "2021-10-03T11:46:20.347Z",
"deletedDt": null,
"id": 1,
"nickname": "string1",
"isSuperuser": false,
"isStaff": false,
"isActive": true,
"loginPlatform": "manual",
"uid": "string",
"token": "string",
"lastLoginDt": "2021-10-03T11:46:20.347Z"
}
}
],
"areas": [
{
"createdDt": "2021-10-03T11:44:05.962Z",
"updatedDt": "2021-10-03T11:44:05.962Z",
"deletedDt": null,
"id": 1,
"area": "drawing"
},
{
"createdDt": "2021-10-03T11:44:05.962Z",
"updatedDt": "2021-10-03T11:44:05.962Z",
"deletedDt": null,
"id": 2,
"area": "design"
}
],
"photos": []
}
Can anybody help?

adding #UseInterceptors(ClassSerializerInterceptor) to the controller was the key.
Also, the second solution I mentioned above (join) should be preceded.

Related

How to get Product and Quantity information from payment_intent.succeeded event via Webhooks in Stripe?

Here is how I'm initializing the Checkout Process in Node.js.
let email = req.body.email
let product_id = req.body.product_id
let YOUR_DOMAIN = 'http://localhost:8000'
const session = await stripe.checkout.sessions.create({
line_items: [{
price: product_id,
adjustable_quantity: {
enabled: true,
minimum: 1,
maximum: 5,
},
quantity: 1,
}],
customer_email: email,
mode: 'payment',
success_url: `${YOUR_DOMAIN}/payment-success`,
cancel_url: `${YOUR_DOMAIN}/payment-failure`,
});
Here are the events I have subscribed to in Webhooks
payment_intent.succeeded
checkout.session.completed
Object Received in Payment Intent Succeeded
{
"id": "evt_1KEqIxI5cib7rtVMoKMkak96",
"object": "event",
"api_version": "2020-03-02",
"created": 1641453754,
"data": {
"object": {
"id": "pi_1KEqIeI5cib7rtVMcz8zsXys",
"object": "payment_intent",
"amount": 59700,
"amount_capturable": 0,
"amount_received": 59700,
"application": null,
"application_fee_amount": null,
"automatic_payment_methods": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic",
"charges": {
"object": "list",
"data": [{
"id": "ch_1KEqIvI5cib7rtVMYUVn5gfQ",
"object": "charge",
"amount": 59700,
"amount_captured": 59700,
"amount_refunded": 0,
"application": null,
"application_fee": null,
"application_fee_amount": null,
"balance_transaction": "txn_1KEqIwI5cib7rtVMGfJlEahg",
"billing_details": {
"address": {
"city": "NY",
"country": "US",
"line1": "sada",
"line2": "asd",
"postal_code": "10001",
"state": "NY"
},
"email": "test#gmail.com",
"name": "John Doe",
"phone": null
},
"calculated_statement_descriptor": "VIDEOFORM",
"captured": true,
"created": 1641453753,
"currency": "usd",
"customer": "cus_KufeYc1hifvZGA",
"description": null,
"destination": null,
"dispute": null,
"disputed": false,
"failure_code": null,
"failure_message": null,
"fraud_details": {},
"invoice": null,
"livemode": false,
"metadata": {},
"on_behalf_of": null,
"order": null,
"outcome": {
"network_status": "approved_by_network",
"reason": null,
"risk_level": "normal",
"risk_score": 25,
"seller_message": "Payment complete.",
"type": "authorized"
},
"paid": true,
"payment_intent": "pi_1KEqIeI5cib7rtVMcz8zsXys",
"payment_method": "pm_1KEqIuI5cib7rtVMYPWlLV8S",
"payment_method_details": {
"card": {
"brand": "visa",
"checks": {
"address_line1_check": "pass",
"address_postal_code_check": "pass",
"cvc_check": "pass"
},
"country": "US",
"exp_month": 1,
"exp_year": 2023,
"fingerprint": "QaiTi5PATFO8ZoC3",
"funding": "credit",
"installments": null,
"last4": "4242",
"mandate": null,
"network": "visa",
"three_d_secure": null,
"wallet": null
},
"type": "card"
},
"receipt_email": null,
"receipt_number": null,
"receipt_url": "https://pay.stripe.com/receipts/acct_1GhUSuI5cib7rtVM/ch_1KEqIvI5cib7rtVMYUVn5gfQ/rcpt_KufeysPW3LD8Yu47q14iYOIIlcGth9h",
"refunded": false,
"refunds": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_1KEqIvI5cib7rtVMYUVn5gfQ/refunds"
},
"review": null,
"shipping": null,
"source": null,
"source_transfer": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "succeeded",
"transfer_data": null,
"transfer_group": null
}],
"has_more": false,
"total_count": 1,
"url": "/v1/charges?payment_intent=pi_1KEqIeI5cib7rtVMcz8zsXys"
},
"client_secret": "pi_1KEqIeI5cib7rtVMcz8zsXys_secret_uZwm3uziwfaWePgTHENYXeraD",
"confirmation_method": "automatic",
"created": 1641453736,
"currency": "usd",
"customer": "cus_KufeYc1hifvZGA",
"description": null,
"invoice": null,
"last_payment_error": null,
"livemode": false,
"metadata": {},
"next_action": null,
"on_behalf_of": null,
"payment_method": "pm_1KEqIuI5cib7rtVMYPWlLV8S",
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": ["card"],
"processing": null,
"receipt_email": null,
"review": null,
"setup_future_usage": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "succeeded",
"transfer_data": null,
"transfer_group": null
}
},
"livemode": false,
"pending_webhooks": 3,
"request": {
"id": "req_Y87umQuitz9WCc",
"idempotency_key": "a4b6af76-73d8-49b4-8393-9017e673af7e"
},
"type": "payment_intent.succeeded"
}
Object Received in Checkout Session Completed
{
"id": "evt_1KEqQOI5cib7rtVMRwAHWDvV",
"object": "event",
"api_version": "2020-03-02",
"created": 1641454214,
"data": {
"object": {
"id": "cs_test_a1AQ9EKIaxi8dXFAJzZ86xYm5meRkWb9Vu0eLowfkiKgUO4cyToooBzSTd",
"object": "checkout.session",
"after_expiration": null,
"allow_promotion_codes": null,
"amount_subtotal": 59700,
"amount_total": 59700,
"automatic_tax": {
"enabled": false,
"status": null
},
"billing_address_collection": null,
"cancel_url": "http://localhost:8000/payment-failure",
"client_reference_id": null,
"consent": null,
"consent_collection": null,
"currency": "usd",
"customer": "cus_Kuflo6N0n4HTzL",
"customer_details": {
"email": "test#gmail.com",
"phone": null,
"tax_exempt": "none",
"tax_ids": []
},
"customer_email": "test#gmail.com",
"expires_at": 1641540596,
"livemode": false,
"locale": null,
"mode": "payment",
"payment_intent": "pi_1KEqQ4I5cib7rtVMyND6NhQG",
"payment_method_options": {},
"payment_method_types": ["card"],
"payment_status": "paid",
"phone_number_collection": {
"enabled": false
},
"recovered_from": null,
"setup_intent": null,
"shipping": null,
"shipping_address_collection": null,
"shipping_options": [],
"shipping_rate": null,
"status": "complete",
"submit_type": null,
"subscription": null,
"success_url": "http://localhost:8000/payment-success",
"total_details": {
"amount_discount": 0,
"amount_shipping": 0,
"amount_tax": 0
},
"url": null
}
},
"livemode": false,
"pending_webhooks": 4,
"request": {
"id": null,
"idempotency_key": null
},
"type": "checkout.session.completed"
}
I'm unable to figure out how to get the Product ID and the Quantity. Could anyone suggest the right approach here?
You can find the Product and the quantity from the Checkout Session by using expand on the line_items property. The code should look like this.
// In "checkout.session.completed" event handler, get the ID of the Checkout Session
const id = event.data.object.id; // "cs_xxx"
// Retrieve the Checkout Session with expand
const session = await stripe.checkout.sessions.retrieve(id, {
expand: [ "line_items" ]
});
// Get the quantity
console.log(session.line_items.data[0].quantity);
// Get the product ID
console.log(session.line_items.data[0].price.product);

Text length ValidationError in STRAPI with CKEditor

I am using STRAPI with custom rich text editor. I setup from this docs
Now If I write more than 234 word I gives ValidationError in console.
I am trying to increase max text limit but I am not sure it is possible or not and from where we can increase word limit.
Here is I am using STRAPI version v3.6.2
{
"name": "ValidationError",
"value": {
"id": 1,
"title": "news1 edited",
"description": "<p>asssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddDDSDSFd</p>",
"published_at": "2021-11-17T07:19:43.837Z",
"created_by": {
"registrationToken": null,
"lastname": "user",
"preferedLanguage": null,
"blocked": null,
"resetPasswordToken": null,
"isActive": true,
"username": "username",
"id": 1,
"firstname": "user",
"email": "user#email.com"
},
"updated_by": {
"registrationToken": null,
"lastname": "user",
"preferedLanguage": null,
"blocked": null,
"resetPasswordToken": null,
"isActive": true,
"username": "username",
"id": 1,
"firstname": "user",
"email": "user#email.com"
},
"created_at": "2021-11-17T07:09:34.551Z",
"updated_at": "2021-12-06T03:22:38.714Z"
},
"errors": [
"components.Input.error.validation.maxLength"
],
"inner": [
{
"name": "ValidationError",
"value": "<p>asssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddDDSDSFd</p>",
"path": "description",
"type": "max",
"errors": [
"components.Input.error.validation.maxLength"
],
"inner": [],
"message": "components.Input.error.validation.maxLength",
"params": {
"path": "description",
"value": "<p>asssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddDDSDSFd</p>",
"originalValue": "<p>asssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddsdsdsdsdsdsdsdsdsdasssadsdsdsdsdsddDDSDSFd</p>",
"max": 240
}
}
],
"message": "components.Input.error.validation.maxLength"
}

How to update a subscription (adding a pricing plan) by Stripe in Node.js?

I'm building a web app which sells several products, each product corresponds to a pricing plan. All the payment system is managed by Stripe.
It happens very often that a user has a subscription that contains Product A (i.e., one pricing plan), and then he wants to add Product B (i.e., another pricing plan) to the same subscription. I want to know how to achieve this by APIs of Stripe.
There is a webpage of Stripe to update a subscription (e.g., https://dashboard.stripe.com/test/subscriptions/sub_H4pQGW8nnc80vF/edit where sub_H4pQGW8nnc80vF is the subscription ID). Let's assume this customer already has 1 Verificator in the subscription, and then he wants to add 1 Pretty Formula to the same subscription. I do this update via the website. Here is the log:
Here is the full Request POST body:
{
"items": {
"0": {
"billing_thresholds": "",
"deleted": "false",
"id": "si_H4pQal4ZxGzLbW",
"quantity": "1",
"tax_rates": ""
},
"1": {
"billing_thresholds": "",
"plan": "plan_Gz6i9yPVIjrDPX",
"deleted": "false",
"quantity": "1"
}
},
"off_session": "true",
"prorate": "true",
"cancel_at": "",
"days_until_due": "30",
"default_tax_rates": "",
"collection_method": "send_invoice",
"billing_thresholds": "",
"enable_incomplete_payments": "false",
"invoice_settings": {
"description": "",
"send_hosted_payment_email": "true",
"supported_payment_methods": {
"ach_credit_transfer": "false",
"au_becs_debit": "false",
"bancontact": "false",
"card": "true",
"fpx": "false",
"giropay": "false",
"ideal": "false",
"jp_credit_transfer": "false",
"paper_check": "false",
"sepa_credit_transfer": "false",
"sofort": "false"
},
"custom_fields": "",
"footer": ""
},
"default_payment_method": "",
"default_source": ""
}
Here is the full Response body:
{
"id": "sub_H4pQGW8nnc80vF",
"object": "subscription",
"application_fee_percent": null,
"billing_cycle_anchor": 1586597833,
"billing_thresholds": null,
"cancel_at": null,
"cancel_at_period_end": false,
"canceled_at": null,
"collection_method": "send_invoice",
"created": 1586597833,
"current_period_end": 1589189833,
"current_period_start": 1586597833,
"customer": "5e575130651c5721d808d25b",
"customer_email": "sdtikply#gmail.com",
"customer_name": "Thomas Joseph",
"days_until_due": 30,
"default_payment_method": null,
"default_source": null,
"default_tax_rates": [
],
"discount": null,
"ended_at": null,
"invoice_settings": {
"send_hosted_payment_email": true,
"supported_payment_methods": {
"ach_credit_transfer": false,
"au_becs_debit": false,
"bancontact": false,
"card": true,
"fpx": false,
"giropay": false,
"ideal": false,
"jp_credit_transfer": false,
"paper_check": false,
"sepa_credit_transfer": false,
"sofort": false
}
},
"items": {
"object": "list",
"data": [
{
"id": "si_H4pQal4ZxGzLbW",
"object": "subscription_item",
"billing_thresholds": null,
"created": 1586597833,
"metadata": {
},
"plan": {
"id": "plan_Ga6n9yMYCDnHCu",
"object": "plan",
"active": true,
"aggregate_usage": null,
"amount": 500,
"amount_decimal": "500",
"billing_scheme": "per_unit",
"created": 1579512574,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
},
"name": "Verificator",
"nickname": "Verificator",
"owning_merchant": "acct_1CiOQBEV4K2GahYL",
"owning_merchant_info": "acct_1CiOQBEV4K2GahYL",
"product": "prod_Ga6mVdA8KXyZ8I",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": null,
"usage_type": "licensed"
},
"quantity": 1,
"subscription": "sub_H4pQGW8nnc80vF",
"tax_rates": [
]
},
{
"id": "si_H82ES9BdIKZCNG",
"object": "subscription_item",
"billing_thresholds": null,
"created": 1587337381,
"metadata": {
},
"plan": {
"id": "plan_Gz6i9yPVIjrDPX",
"object": "plan",
"active": true,
"aggregate_usage": null,
"amount": 500,
"amount_decimal": "500",
"billing_scheme": "per_unit",
"created": 1585278262,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
},
"name": "Pretty Formula",
"nickname": "Pretty Formula",
"owning_merchant": "acct_1CiOQBEV4K2GahYL",
"owning_merchant_info": "acct_1CiOQBEV4K2GahYL",
"product": "prod_GxqkRFdI08DvyR",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": null,
"usage_type": "licensed"
},
"quantity": 1,
"subscription": "sub_H4pQGW8nnc80vF",
"tax_rates": [
]
}
],
"has_more": false,
"total_count": 2,
"url": "/v1/subscription_items?subscription=sub_H4pQGW8nnc80vF"
},
"latest_invoice": "in_1GWfm1EV4K2GahYLlmtUEISo",
"livemode": false,
"metadata": {
},
"next_pending_invoice_item_invoice": null,
"owning_merchant": "acct_1CiOQBEV4K2GahYL",
"owning_merchant_info": "acct_1CiOQBEV4K2GahYL",
"pause_collection": null,
"pending_invoice_item_interval": null,
"pending_setup_intent": null,
"pending_update": null,
"plan": null,
"quantity": null,
"schedule": null,
"start_date": 1586597833,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
}
So my question is, how can I code in my backend (Node.js) to achieve exactly the same thing?
You just need to use the Update Subscription API and provide the items portion just as you're seeing above:
"items": {
"0": {
"billing_thresholds": "",
"deleted": "false",
"id": "si_H4pQal4ZxGzLbW",
"quantity": "1",
"tax_rates": ""
},
"1": {
"billing_thresholds": "",
"plan": "plan_Gz6i9yPVIjrDPX",
"deleted": "false",
"quantity": "1"
}
},
The first item is the existing Subscription Item (si_), and the second one is the new one you want to add.

Sequelize - Search using the associated table but exclude results from the associated table

Is it possible to search using the associated table but excluding the data in the associated table?
E.g.
db.Bill.findAll({
include: [{
model: self.db.Group,
where: {
id: groupId
},
include: [{
model: self.db.Account,
where: {username: username}
}]
}]
});
Currently, I get these results...
[
{
"id": 2,
"title": "Title",
"category": "OTHERS",
"currency": "php",
"recurring": false,
"date_from": null,
"date_to": null,
"createdAt": "2015-08-12T10:54:08.000Z",
"updatedAt": "2015-08-12T10:54:08.000Z",
"group_id": 2,
"Group": {
"id": 2,
"name": "Group",
"createdAt": "2015-08-12T10:54:07.000Z",
"updatedAt": "2015-08-12T10:54:07.000Z",
"Account": {
"username": "username"
}
}
}
]
I want to find all the bills under a group but I only want the results to be
[
{
"id": 2,
"title": "Title",
"category": "OTHERS",
"currency": "php",
"recurring": false,
"date_from": null,
"date_to": null,
"createdAt": "2015-08-12T10:54:08.000Z",
"updatedAt": "2015-08-12T10:54:08.000Z",
"group_id": 2
}
];

Get Organization ID or domain from Azure AD Graph

We're developing a multi-tenant SSO integration with Office 365 using the new OpenID implementation.
Once the access token has been retrieved, we call https://graph.windows.net/me?api-version=1.21-preview to get the user's profile information which gives something like the below - great.
{
"odata.metadata": "https:\/\/graph.windows.net\/myorganization\/$metadata#directoryObjects\/Microsoft.WindowsAzure.ActiveDirectory.User\/#Element",
"odata.type": "Microsoft.WindowsAzure.ActiveDirectory.User",
"objectType": "User",
"objectId": "GUID",
"accountEnabled": true,
"assignedLicenses": [
],
"assignedPlans": [
],
"city": null,
"country": null,
"department": null,
"dirSyncEnabled": null,
"displayName": "Tester A",
"facsimileTelephoneNumber": null,
"givenName": "Test",
"immutableId": null,
"jobTitle": null,
"lastDirSyncTime": null,
"mail": null,
"mailNickname": "tester-a",
"mobile": null,
"otherMails": [
],
"passwordPolicies": "None",
"passwordProfile": null,
"physicalDeliveryOfficeName": null,
"postalCode": null,
"preferredLanguage": null,
"provisionedPlans": [
],
"provisioningErrors": [
],
"proxyAddresses": [
],
"state": null,
"streetAddress": null,
"surname": "A",
"telephoneNumber": null,
"usageLocation": null,
"userPrincipalName": "tester-a#test.onmicrosoft.com",
"userType": "Member"
}
However, it doesn't seem to return any identifier or specific domain for the organization - other than the domain contained in the userPrincipalName field. Is there a better way to identify the organization (considering the organization may update test.onmicrosoft.com to a custom domain of test.microsoft.com)?
Indeed. Use the tenantDetails API (https://graph.windows.net/{tenantDomain}/tenantDetails?api-version={version}), to get the display name of the directory and all verified domains associated with it. Documented here: http://msdn.microsoft.com/en-us/library/azure/hh974467.aspx.
Below is the trimmed output for my tenant.
Hope this helps.
{
"odata.metadata": "https://graph.windows.net/dushyantgill.com/$metadata#directoryObjects/Microsoft.WindowsAzure.ActiveDirectory.TenantDetail",
"value": [
{
"odata.type": "Microsoft.WindowsAzure.ActiveDirectory.TenantDetail",
"objectType": "Company",
"objectId": "62e173e9-301e-423e-bcd4-29121ec1aa24",
"assignedPlans": [
{
"assignedTimestamp": "2013-09-17T01:01:58Z",
"capabilityStatus": "Enabled",
"service": "SharePoint",
"servicePlanId": "a1f3d0a8-84c0-4ae0-bae4-685917b8ab48"
} [SNIP]
],
"city": "Redmond",
"companyLastDirSyncTime": "2014-04-20T17:42:58Z",
"country": null,
"countryLetterCode": "US",
"dirSyncEnabled": true,
"displayName": "dushyantgill",
"marketingNotificationEmails": [],
"postalCode": "98052",
"preferredLanguage": "en",
"provisionedPlans": [
{
"capabilityStatus": "Enabled",
"provisioningStatus": "Success",
"service": "exchange"
}[SNIP]
],
"provisioningErrors": [],
"state": "WA",
"street": "[SNIP]",
"technicalNotificationMails": [
"[SNIP]"
],
"telephoneNumber": null,
"tenantType": null,
"verifiedDomains": [
{
"capabilities": "Email, OfficeCommunicationsOnline",
"default": false,
"id": "0005000080186A52",
"initial": false,
"name": "dushyantgill.mail.onmicrosoft.com",
"type": "Managed"
},
{
"capabilities": "Email, OfficeCommunicationsOnline",
"default": false,
"id": "00057FFE803C0EDA",
"initial": false,
"name": "dushyantgill.org",
"type": "Federated"
},
{
"capabilities": "Email, OfficeCommunicationsOnline",
"default": true,
"id": "00053FFF80232F54",
"initial": false,
"name": "dushyantgill.com",
"type": "Managed"
}[SNIP]
]
}
]
}

Resources